openfox 2.0.110 → 2.0.112

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 (80) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +1 -0
  3. package/dist/CHANGELOG.md +25 -0
  4. package/dist/{ask-CJMU6EW7.js → ask-ZYPCJKZD.js} +3 -2
  5. package/dist/{chat-handler-UZ7WTT6D.js → chat-handler-BYXZIIV3.js} +23 -22
  6. package/dist/{chunk-VJWWJEBX.js → chunk-3UILDGOO.js} +9 -9
  7. package/dist/{chunk-GNFDD6LN.js → chunk-BOSKQI62.js} +3 -3
  8. package/dist/{chunk-D6ODGTSZ.js → chunk-C372UH7N.js} +2 -1
  9. package/dist/{chunk-4ZXRERIW.js → chunk-C5NQF2K4.js} +46 -4
  10. package/dist/{chunk-3HS72YIE.js → chunk-ERYUSG5C.js} +2 -2
  11. package/dist/{chunk-PU3IPUSW.js → chunk-FFPCVN5M.js} +45 -8
  12. package/dist/{chunk-KDQJOI2I.js → chunk-FSYRANYR.js} +2 -2
  13. package/dist/chunk-IJ53Y77N.js +142 -0
  14. package/dist/{chunk-ZJW3KOII.js → chunk-IYTDCPEQ.js} +293 -98
  15. package/dist/{chunk-WCQOHRUX.js → chunk-JDT63SSP.js} +2 -2
  16. package/dist/{chunk-VT2X3DMC.js → chunk-JNHKKUGJ.js} +2 -2
  17. package/dist/{chunk-JAX5OEMM.js → chunk-JURM3RPZ.js} +21 -4
  18. package/dist/chunk-LCLH6ZUL.js +43 -0
  19. package/dist/{chunk-6EV7X5MP.js → chunk-N4RTAGFY.js} +2 -2
  20. package/dist/{chunk-LXYNP7LL.js → chunk-NB2D6I64.js} +221 -5
  21. package/dist/{chunk-VKWVPQJ5.js → chunk-OAN4BXEW.js} +3 -1
  22. package/dist/{chunk-4R7G5JB6.js → chunk-P45RJGOT.js} +1 -1
  23. package/dist/chunk-P5AA7OYJ.js +7 -0
  24. package/dist/{chunk-E5HZKNTY.js → chunk-PCC4DBPF.js} +2 -2
  25. package/dist/{chunk-ACJNRPTO.js → chunk-QGXLZZBS.js} +29 -21
  26. package/dist/{chunk-UCYPPLVR.js → chunk-RAKPI4OE.js} +81 -70
  27. package/dist/{chunk-MM46DJJL.js → chunk-RISQXU32.js} +2 -2
  28. package/dist/{chunk-CQKRZ4WV.js → chunk-RKMP74BB.js} +4 -4
  29. package/dist/chunk-RSB4AR2A.js +108 -0
  30. package/dist/{chunk-VXKPZUCT.js → chunk-RT2A2RRL.js} +4 -2
  31. package/dist/{chunk-HK75Q3EA.js → chunk-SDGNV45R.js} +10 -10
  32. package/dist/{chunk-C5JJM72V.js → chunk-SVJFMZ2Q.js} +49 -5
  33. package/dist/{chunk-B5MH4HQ6.js → chunk-SYJMUIRC.js} +7 -3
  34. package/dist/{chunk-QRASX3HC.js → chunk-UAF2FOI5.js} +7 -7
  35. package/dist/{chunk-4HIFB7F5.js → chunk-XCK5IBO4.js} +37 -26
  36. package/dist/{chunk-5HMKLHTT.js → chunk-XWNCKIPO.js} +2 -2
  37. package/dist/{chunk-NORNB6IJ.js → chunk-Z56SEG4Z.js} +6 -6
  38. package/dist/cli/dev.js +1 -1
  39. package/dist/cli/index.js +1 -1
  40. package/dist/{client-LPNFUOPV.js → client-QNQTX5EA.js} +4 -4
  41. package/dist/{compactor-OSDLCGRC.js → compactor-X2KZ3XFU.js} +10 -9
  42. package/dist/{config-HX7FDKGJ.js → config-TW5FHQEM.js} +2 -2
  43. package/dist/{dynamic-context-WVA7HTEP.js → dynamic-context-ZRQO2FJN.js} +7 -7
  44. package/dist/{events-26J7BUSY.js → events-Y6XXQYFG.js} +7 -6
  45. package/dist/{folding-ZD4AMFNR.js → folding-Z4GNWRC3.js} +9 -6
  46. package/dist/{http-client-MQARNFY3.js → http-client-2GDKHZIG.js} +3 -3
  47. package/dist/{manager-RJH7EYIG.js → manager-HCMDFEQH.js} +4 -4
  48. package/dist/{model-overrides-BXMFIT47.js → model-overrides-O3ZYKFP7.js} +3 -3
  49. package/dist/oauth-provider-52YILVUJ.js +15 -0
  50. package/dist/oauth-store-XCFXV2VM.js +32 -0
  51. package/dist/{orchestrator-BW27C4K4.js → orchestrator-P5EUMC7E.js} +22 -21
  52. package/dist/package.json +13 -10
  53. package/dist/{path-security-AAZMH33K.js → path-security-525YLND3.js} +11 -9
  54. package/dist/{platform-EZJABX5J.js → platform-MEQUWG6U.js} +3 -3
  55. package/dist/{processor-FTCPHWBM.js → processor-UN4H4V7F.js} +22 -21
  56. package/dist/{protocol-_Gphic7p.d.ts → protocol-D6MISQyz.d.ts} +8 -3
  57. package/dist/{protocol-SPIJPOEN.js → protocol-FTHAR2YL.js} +4 -3
  58. package/dist/{provider-JS5P3HQ2.js → provider-3R4X62LW.js} +7 -7
  59. package/dist/{provider-manager-MWAIOX2A.js → provider-manager-W5N4XRE5.js} +5 -5
  60. package/dist/{registry-JJB5GXOM.js → registry-74KPZ5NV.js} +3 -3
  61. package/dist/{serve-XDZB4EJN.js → serve-WHFUNQ6Z.js} +32 -29
  62. package/dist/server/index.d.ts +15 -1
  63. package/dist/server/index.js +31 -28
  64. package/dist/server-7MOOJR2N.js +48 -0
  65. package/dist/{session-overrides-T47KXDDS.js → session-overrides-XH6I3COP.js} +5 -5
  66. package/dist/{sessions-YTWCOHI3.js → sessions-D772YTWL.js} +8 -4
  67. package/dist/{settings-2RZBMX5Y.js → settings-KO6DSJLD.js} +2 -2
  68. package/dist/shared/index.d.ts +1 -1
  69. package/dist/shared/index.js +1 -1
  70. package/dist/{tools-KPIYFL5A.js → tools-HTUTYMKI.js} +20 -19
  71. package/dist/{update-75QZJYKD.js → update-BRUFGGTW.js} +2 -2
  72. package/dist/{update-server-4I6LXE5K.js → update-server-LOOXIXDW.js} +2 -2
  73. package/dist/web/assets/{index-BmjVoqQT.js → index-Dukvfqm-.js} +83 -83
  74. package/dist/web/assets/{index-CyWbbpRP.css → index-nS1p0g8O.css} +1 -1
  75. package/dist/web/index.html +2 -2
  76. package/dist/web/sw.js +1 -1
  77. package/package.json +13 -10
  78. package/scripts/postinstall.mjs +8 -0
  79. package/dist/chunk-64374FPB.js +0 -7
  80. package/dist/server-R6DDJNF3.js +0 -47
package/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.0.112 - 2026-08-03
4
+
5
+ ### Bug Fixes
6
+
7
+ - **Updates install again** — the postinstall script is now bundled with the release, so `openfox update` no longer fails halfway with a missing file
8
+
9
+ ## 2.0.111 - 2026-08-03
10
+
11
+ ### Enhancements
12
+
13
+ - **OAuth login for MCP servers** — servers that require OAuth authorization now connect through a browser-based login flow instead of failing
14
+ - **Manual model entry in the provider setup** — if a provider exposes no model list, type the model name directly instead of hitting a dead-end "No models found"
15
+ - **You choose when to restart after an update** — updates download first and restart on your OK; service installs can opt into automatic restart
16
+ - **Homepage loads faster** — the session list shows the five most recent per project up front and fills in the rest lazily
17
+ - **Leaner session storage** — finished tool-call streaming buffers are dropped from snapshots and stale backups auto-prune after 10 days
18
+
19
+ ### Bug Fixes
20
+
21
+ - **Tool calls no longer misread as interrupted** — an output that merely contains the interrupt marker text now shows as successful
22
+ - **Multi-statement shell commands keep their tails** — output is no longer cut at the first line for compound commands
23
+ - **Windows paths shorten to names again** — workspace and file names show their basename instead of the full path
24
+ - **Auto-compaction honors configured thresholds** — the internal cap is raised from 85%, so thresholds up to 95% work as set
25
+ - **Windows path-safety gaps closed** — dangerous commands outside the workdir are confirmed again in edge cases, including under Git Bash
26
+ - **Choice options survive reloads** — structured choices stay stable across page refreshes
27
+
3
28
  ## 2.0.110 - 2026-08-02
4
29
 
5
30
  ### Bug Fixes
package/README.md CHANGED
@@ -139,6 +139,7 @@ _Vision Fallback — Image processing configuration_
139
139
  | `OPENFOX_LLM_IDLE_TIMEOUT` | `300000` | LLM stream idle timeout in ms |
140
140
  | `OPENFOX_PORT` | `10369` | Server listen port |
141
141
  | `OPENFOX_HOST` | `127.0.0.1` | Server bind host |
142
+ | `OPENFOX_PUBLIC_URL` | — | Public origin used to build the MCP OAuth redirect URI |
142
143
  | `OPENFOX_WORKDIR` | `cwd` | Working directory |
143
144
  | `OPENFOX_DB_PATH` | `./openfox.db` | SQLite database path |
144
145
  | `OPENFOX_LOG_LEVEL` | `info` | Log level: `debug`, `info`, `warn`, `error` |
package/dist/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.0.112 - 2026-08-03
4
+
5
+ ### Bug Fixes
6
+
7
+ - **Updates install again** — the postinstall script is now bundled with the release, so `openfox update` no longer fails halfway with a missing file
8
+
9
+ ## 2.0.111 - 2026-08-03
10
+
11
+ ### Enhancements
12
+
13
+ - **OAuth login for MCP servers** — servers that require OAuth authorization now connect through a browser-based login flow instead of failing
14
+ - **Manual model entry in the provider setup** — if a provider exposes no model list, type the model name directly instead of hitting a dead-end "No models found"
15
+ - **You choose when to restart after an update** — updates download first and restart on your OK; service installs can opt into automatic restart
16
+ - **Homepage loads faster** — the session list shows the five most recent per project up front and fills in the rest lazily
17
+ - **Leaner session storage** — finished tool-call streaming buffers are dropped from snapshots and stale backups auto-prune after 10 days
18
+
19
+ ### Bug Fixes
20
+
21
+ - **Tool calls no longer misread as interrupted** — an output that merely contains the interrupt marker text now shows as successful
22
+ - **Multi-statement shell commands keep their tails** — output is no longer cut at the first line for compound commands
23
+ - **Windows paths shorten to names again** — workspace and file names show their basename instead of the full path
24
+ - **Auto-compaction honors configured thresholds** — the internal cap is raised from 85%, so thresholds up to 95% work as set
25
+ - **Windows path-safety gaps closed** — dangerous commands outside the workdir are confirmed again in edge cases, including under Git Bash
26
+ - **Choice options survive reloads** — structured choices stay stable across page refreshes
27
+
3
28
  ## 2.0.110 - 2026-08-02
4
29
 
5
30
  ### Bug Fixes
@@ -7,7 +7,8 @@ import {
7
7
  getPendingQuestionsForSession,
8
8
  hasPendingQuestion,
9
9
  provideAnswer
10
- } from "./chunk-JAX5OEMM.js";
10
+ } from "./chunk-JURM3RPZ.js";
11
+ import "./chunk-LCLH6ZUL.js";
11
12
  import "./chunk-5WRI5ZAA.js";
12
13
  export {
13
14
  AskUserInterrupt,
@@ -19,4 +20,4 @@ export {
19
20
  hasPendingQuestion,
20
21
  provideAnswer
21
22
  };
22
- //# sourceMappingURL=ask-CJMU6EW7.js.map
23
+ //# sourceMappingURL=ask-ZYPCJKZD.js.map
@@ -2,48 +2,49 @@ import {
2
2
  buildRunChatTurnParams,
3
3
  finalizeTurnCompletion,
4
4
  generateSessionNameForSession
5
- } from "./chunk-VJWWJEBX.js";
5
+ } from "./chunk-3UILDGOO.js";
6
6
  import {
7
7
  runChatTurn
8
- } from "./chunk-HK75Q3EA.js";
9
- import "./chunk-NORNB6IJ.js";
10
- import "./chunk-UCYPPLVR.js";
11
- import "./chunk-GNFDD6LN.js";
8
+ } from "./chunk-SDGNV45R.js";
9
+ import "./chunk-Z56SEG4Z.js";
10
+ import "./chunk-RAKPI4OE.js";
11
+ import "./chunk-BOSKQI62.js";
12
12
  import "./chunk-JR54MDZI.js";
13
- import "./chunk-5HMKLHTT.js";
13
+ import "./chunk-XWNCKIPO.js";
14
14
  import "./chunk-33Q7LCVD.js";
15
- import "./chunk-C5JJM72V.js";
15
+ import "./chunk-SVJFMZ2Q.js";
16
16
  import "./chunk-I72ACQ6R.js";
17
17
  import "./chunk-JE7LW7Y6.js";
18
- import "./chunk-VKWVPQJ5.js";
18
+ import "./chunk-OAN4BXEW.js";
19
19
  import "./chunk-FR5LUTLQ.js";
20
20
  import "./chunk-J7GAZGZT.js";
21
- import "./chunk-WCQOHRUX.js";
22
- import "./chunk-PU3IPUSW.js";
21
+ import "./chunk-JDT63SSP.js";
22
+ import "./chunk-FFPCVN5M.js";
23
23
  import {
24
24
  getEventStore
25
- } from "./chunk-LXYNP7LL.js";
25
+ } from "./chunk-NB2D6I64.js";
26
26
  import {
27
27
  createChatMessageMessage,
28
28
  createPhaseChangedMessage,
29
29
  createSessionRunningMessage
30
- } from "./chunk-B5MH4HQ6.js";
31
- import "./chunk-JAX5OEMM.js";
32
- import "./chunk-6EV7X5MP.js";
33
- import "./chunk-MM46DJJL.js";
30
+ } from "./chunk-SYJMUIRC.js";
31
+ import "./chunk-N4RTAGFY.js";
32
+ import "./chunk-JURM3RPZ.js";
33
+ import "./chunk-RISQXU32.js";
34
34
  import "./chunk-6FPGJR7O.js";
35
- import "./chunk-ACJNRPTO.js";
36
- import "./chunk-4ZXRERIW.js";
37
- import "./chunk-VT2X3DMC.js";
35
+ import "./chunk-QGXLZZBS.js";
36
+ import "./chunk-LCLH6ZUL.js";
37
+ import "./chunk-C5NQF2K4.js";
38
+ import "./chunk-JNHKKUGJ.js";
38
39
  import "./chunk-J2GP3J3X.js";
39
40
  import "./chunk-V4IE7HJY.js";
40
41
  import "./chunk-YHEQTVFV.js";
41
42
  import "./chunk-L737Y63F.js";
42
- import "./chunk-VXKPZUCT.js";
43
+ import "./chunk-RT2A2RRL.js";
43
44
  import "./chunk-LCQ5AN6Y.js";
44
45
  import "./chunk-K44MW7JJ.js";
45
- import "./chunk-4R7G5JB6.js";
46
- import "./chunk-D6ODGTSZ.js";
46
+ import "./chunk-P45RJGOT.js";
47
+ import "./chunk-C372UH7N.js";
47
48
  import "./chunk-CQGTEGKL.js";
48
49
  import "./chunk-5WRI5ZAA.js";
49
50
 
@@ -166,4 +167,4 @@ export {
166
167
  startChatSession,
167
168
  stopSessionExecution
168
169
  };
169
- //# sourceMappingURL=chat-handler-UZ7WTT6D.js.map
170
+ //# sourceMappingURL=chat-handler-BYXZIIV3.js.map
@@ -1,27 +1,27 @@
1
1
  import {
2
2
  combineEventsWithSnapshot,
3
3
  getEventStore
4
- } from "./chunk-LXYNP7LL.js";
4
+ } from "./chunk-NB2D6I64.js";
5
5
  import {
6
6
  createContextStateMessage,
7
7
  createSessionStateMessage
8
- } from "./chunk-B5MH4HQ6.js";
8
+ } from "./chunk-SYJMUIRC.js";
9
9
  import {
10
10
  getPendingQuestionsForSession
11
- } from "./chunk-JAX5OEMM.js";
11
+ } from "./chunk-JURM3RPZ.js";
12
12
  import {
13
13
  buildMessagesFromStoredEvents,
14
14
  foldPendingConfirmations
15
- } from "./chunk-ACJNRPTO.js";
15
+ } from "./chunk-QGXLZZBS.js";
16
16
  import {
17
17
  updateSessionMetadata
18
- } from "./chunk-4ZXRERIW.js";
18
+ } from "./chunk-C5NQF2K4.js";
19
19
  import {
20
20
  getRuntimeConfig
21
- } from "./chunk-VT2X3DMC.js";
21
+ } from "./chunk-JNHKKUGJ.js";
22
22
  import {
23
23
  getMaxVisibleItems
24
- } from "./chunk-VXKPZUCT.js";
24
+ } from "./chunk-RT2A2RRL.js";
25
25
  import {
26
26
  logger
27
27
  } from "./chunk-K44MW7JJ.js";
@@ -153,7 +153,7 @@ async function generateSessionNameForSession(sessionId, userMessage, deps, signa
153
153
  client = deps.getLLMClient();
154
154
  client.setModel(providerConfig.model);
155
155
  } else if (providerConfig) {
156
- const { createLLMClient } = await import("./client-LPNFUOPV.js");
156
+ const { createLLMClient } = await import("./client-QNQTX5EA.js");
157
157
  client = createLLMClient({
158
158
  llm: {
159
159
  baseUrl: providerConfig.baseUrl,
@@ -204,4 +204,4 @@ export {
204
204
  needsNameGeneration,
205
205
  generateSessionNameForSession
206
206
  };
207
- //# sourceMappingURL=chunk-VJWWJEBX.js.map
207
+ //# sourceMappingURL=chunk-3UILDGOO.js.map
@@ -5,13 +5,13 @@ import {
5
5
  deleteItemFromDir,
6
6
  loadItemsFromDir,
7
7
  pathExists
8
- } from "./chunk-VT2X3DMC.js";
8
+ } from "./chunk-JNHKKUGJ.js";
9
9
  import {
10
10
  SETTINGS_KEYS,
11
11
  deleteSetting,
12
12
  getSetting,
13
13
  setSetting
14
- } from "./chunk-VXKPZUCT.js";
14
+ } from "./chunk-RT2A2RRL.js";
15
15
 
16
16
  // src/server/context/instructions.ts
17
17
  import { readFile, access } from "fs/promises";
@@ -440,4 +440,4 @@ export {
440
440
  deleteSkill,
441
441
  deleteProjectSkill
442
442
  };
443
- //# sourceMappingURL=chunk-GNFDD6LN.js.map
443
+ //# sourceMappingURL=chunk-BOSKQI62.js.map
@@ -108,6 +108,7 @@ var mcpServerSchema = z.object({
108
108
  env: z.record(z.string(), z.string()).optional(),
109
109
  url: z.string().optional(),
110
110
  headers: z.record(z.string(), z.string()).optional(),
111
+ oauth: z.boolean().optional(),
111
112
  disabledTools: z.array(z.string()).optional(),
112
113
  cachedTools: z.array(cachedToolSchema).optional(),
113
114
  timeout: z.number().positive().optional(),
@@ -370,4 +371,4 @@ export {
370
371
  removeProvider,
371
372
  activateProvider
372
373
  };
373
- //# sourceMappingURL=chunk-D6ODGTSZ.js.map
374
+ //# sourceMappingURL=chunk-C372UH7N.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  resolveDefaultAgentId
3
- } from "./chunk-VT2X3DMC.js";
3
+ } from "./chunk-JNHKKUGJ.js";
4
4
  import {
5
5
  getDatabase
6
6
  } from "./chunk-LCQ5AN6Y.js";
@@ -245,7 +245,14 @@ function listSessions() {
245
245
  return rows.map(mapSessionSummaryRow);
246
246
  }
247
247
  function listSessionsByProject(projectId, limit = 20, offset = 0) {
248
+ return listSessionsPaged(projectId, limit, offset);
249
+ }
250
+ function listSessionsLimited(limit = 20, offset = 0) {
251
+ return listSessionsPaged(null, limit, offset);
252
+ }
253
+ function listSessionsPaged(projectId, limit, offset) {
248
254
  const db = getDatabase();
255
+ const where = projectId ? "WHERE s.project_id = ?" : "";
249
256
  const rows = db.prepare(
250
257
  `
251
258
  SELECT
@@ -264,15 +271,48 @@ function listSessionsByProject(projectId, limit = 20, offset = 0) {
264
271
  s.provider_model,
265
272
  s.message_count
266
273
  FROM sessions s
267
- WHERE s.project_id = ?
274
+ ${where}
268
275
  ORDER BY s.updated_at DESC
269
276
  LIMIT ? OFFSET ?
270
277
  `
271
- ).all(projectId, limit + 1, offset);
278
+ ).all(...projectId ? [projectId] : [], limit + 1, offset);
272
279
  const hasMore = rows.length > limit;
273
280
  const sessions = rows.slice(0, limit).map(mapSessionSummaryRow);
274
281
  return { sessions, hasMore };
275
282
  }
283
+ function listHomeSessions(sessionsPerProject = 5) {
284
+ const db = getDatabase();
285
+ const rows = db.prepare(
286
+ `
287
+ SELECT
288
+ s.id,
289
+ s.project_id,
290
+ s.workdir,
291
+ s.workspace,
292
+ s.branch,
293
+ s.mode,
294
+ s.workflow_phase,
295
+ s.is_running,
296
+ s.created_at,
297
+ s.updated_at,
298
+ s.title,
299
+ s.provider_id,
300
+ s.provider_model,
301
+ s.message_count
302
+ FROM sessions s
303
+ ORDER BY s.updated_at DESC
304
+ `
305
+ ).all();
306
+ const seen = /* @__PURE__ */ new Map();
307
+ const result = [];
308
+ for (const row of rows) {
309
+ const count = seen.get(row.project_id) ?? 0;
310
+ if (count >= sessionsPerProject) continue;
311
+ seen.set(row.project_id, count + 1);
312
+ result.push(mapSessionSummaryRow(row));
313
+ }
314
+ return result;
315
+ }
276
316
  function updateSessionWorkdir(id, workdir, workspace, branch) {
277
317
  const db = getDatabase();
278
318
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -360,6 +400,8 @@ export {
360
400
  getSessionMessageCount,
361
401
  listSessions,
362
402
  listSessionsByProject,
403
+ listSessionsLimited,
404
+ listHomeSessions,
363
405
  updateSessionWorkdir,
364
406
  updateSessionBranch,
365
407
  deleteSession,
@@ -368,4 +410,4 @@ export {
368
410
  getActiveWorkflowExecution,
369
411
  clearWorkflowExecution
370
412
  };
371
- //# sourceMappingURL=chunk-4ZXRERIW.js.map
413
+ //# sourceMappingURL=chunk-C5NQF2K4.js.map
@@ -17,7 +17,7 @@ import {
17
17
  import {
18
18
  LLMError,
19
19
  OpenAIHttpClient
20
- } from "./chunk-E5HZKNTY.js";
20
+ } from "./chunk-PCC4DBPF.js";
21
21
  import {
22
22
  logger
23
23
  } from "./chunk-K44MW7JJ.js";
@@ -310,4 +310,4 @@ function createLLMClient(config, initialBackend = "unknown") {
310
310
  export {
311
311
  createLLMClient
312
312
  };
313
- //# sourceMappingURL=chunk-3HS72YIE.js.map
313
+ //# sourceMappingURL=chunk-ERYUSG5C.js.map
@@ -1,9 +1,12 @@
1
1
  import {
2
2
  getEventStore
3
- } from "./chunk-LXYNP7LL.js";
3
+ } from "./chunk-NB2D6I64.js";
4
4
  import {
5
5
  createChatPathConfirmationMessage
6
- } from "./chunk-B5MH4HQ6.js";
6
+ } from "./chunk-SYJMUIRC.js";
7
+ import {
8
+ getPlatformShell
9
+ } from "./chunk-N4RTAGFY.js";
7
10
 
8
11
  // src/server/tools/path-security.ts
9
12
  import { realpath } from "fs/promises";
@@ -120,11 +123,19 @@ function looksLikeRegex(str) {
120
123
  return /[*?+[\]\\]/.test(str);
121
124
  }
122
125
  var isWindows = () => process.platform === "win32";
126
+ function usesPosixPaths() {
127
+ if (process.platform !== "win32") return true;
128
+ return /^(?:ba|z|)sh(?:\.exe)?$/i.test(win32.basename(getPlatformShell().command));
129
+ }
123
130
  function isWindowsAbsolutePath(str) {
124
131
  return /^[A-Za-z]:[\\/]/.test(str);
125
132
  }
126
133
  function normalizeExtracted(path) {
127
- return isWindowsAbsolutePath(path) ? win32.normalize(path) : posix.normalize(path);
134
+ if (isWindowsAbsolutePath(path)) return win32.normalize(path);
135
+ if (isWindows() && /^\/[A-Za-z]\//.test(path)) {
136
+ return win32.normalize(`${path[1].toUpperCase()}:\\${path.slice(3)}`);
137
+ }
138
+ return posix.normalize(path);
128
139
  }
129
140
  function isPlaceholderToken(str) {
130
141
  return str.includes("__URL__") || str.includes("__FILEURL__") || str.includes("__SED__") || str.includes("__COMMIT_MSG__");
@@ -135,6 +146,7 @@ function extractAbsolutePathsFromCommand(command) {
135
146
  }
136
147
  const paths = [];
137
148
  const home = homedir();
149
+ const posixShell = usesPosixPaths();
138
150
  let sanitized = command.replace(/https?:\/\/[^\s'"]+/g, " __URL__ ").replace(/ftp:\/\/[^\s'"]+/g, " __URL__ ");
139
151
  sanitized = sanitized.replace(/(?<!\w)s\/[^/]*\/[^/]*\/[gip]*/g, " __SED__ ");
140
152
  sanitized = sanitized.replace(/(?<!\w)s\|[^|]*\|[^|]*\|[gip]*/g, " __SED__ ");
@@ -175,7 +187,7 @@ function extractAbsolutePathsFromCommand(command) {
175
187
  if (!isSafePath(resolved)) {
176
188
  paths.push(resolved);
177
189
  }
178
- } else if (!isWindows() && content.startsWith("/")) {
190
+ } else if (posixShell && content.startsWith("/")) {
179
191
  const resolved = normalizeExtracted(content);
180
192
  if (!isSafePath(resolved)) {
181
193
  paths.push(resolved);
@@ -199,7 +211,8 @@ function extractAbsolutePathsFromCommand(command) {
199
211
  paths.push(resolved);
200
212
  }
201
213
  }
202
- } else {
214
+ }
215
+ if (posixShell) {
203
216
  const absolutePattern = /(?:^|[\s=(])(\/[^\s"'|&;<>`()]+)/g;
204
217
  while ((match = absolutePattern.exec(sanitized)) !== null) {
205
218
  const candidate = match[1];
@@ -238,9 +251,12 @@ function extractSensitivePathsFromCommand(command) {
238
251
  }
239
252
  return [...new Set(paths)];
240
253
  }
254
+ var WINDOWS_DEVICE_NAMES = /* @__PURE__ */ new Set(["nul", "con", "prn", "aux"]);
241
255
  function isSafePath(path) {
242
256
  const normalized = posix.normalize(path);
243
- return SAFE_PATHS.has(normalized);
257
+ if (SAFE_PATHS.has(normalized)) return true;
258
+ if (!isWindows()) return false;
259
+ return WINDOWS_DEVICE_NAMES.has(win32.basename(path.replace(/^\\\\[.?]\\/, "")).toLowerCase());
244
260
  }
245
261
  async function checkPathsAccess(paths, workdir, sessionId) {
246
262
  if (paths.length === 0) {
@@ -274,9 +290,30 @@ var DANGEROUS_PATTERNS = [
274
290
  /dd\s+if=/,
275
291
  /:\(\)\s*\{\s*:\s*\|\s*:\s*&\s*\}\s*;/
276
292
  ];
293
+ var WINDOWS_DANGEROUS_PATTERNS = [
294
+ /\b(?:rd|rmdir)\s+(?:\/[a-z]\s+)*\/s\b/i,
295
+ // rd /s /q <dir>
296
+ /\bdel\s+(?:\/[a-z]\s+)*\/s\b/i,
297
+ // del /f /s /q <pattern>
298
+ // The operand is a bare drive ("D:", "D:\"), never a file path — that is what
299
+ // keeps "npm run format -- C:\src\x.ts" out of the dangerous bucket.
300
+ /\bformat\s+(?:\/\S+\s+)*[a-z]:\\?(?=\s|$)/i,
301
+ // format D: / format /q D: / format /fs:NTFS D:
302
+ /\bRemove-Item\b(?=[^|;]*-Recurse\b)(?=[^|;]*-Force\b)/i,
303
+ // PowerShell recursive force delete (flag order-independent)
304
+ /\brunas\b/i,
305
+ // sudo equivalent
306
+ /\bStart-Process\b[^|;]*-Verb\s+RunAs\b/i,
307
+ // sudo equivalent (PowerShell)
308
+ /\bicacls\b[^|;]*\/grant\b[^|;]*Everyone/i,
309
+ // chmod 777 equivalent
310
+ /\bdiskpart\b/i
311
+ // raw disk write, dd/mkfs equivalent
312
+ ];
277
313
  function extractDangerousPatterns(command) {
314
+ const patterns = isWindows() ? [...DANGEROUS_PATTERNS, ...WINDOWS_DANGEROUS_PATTERNS] : DANGEROUS_PATTERNS;
278
315
  const dangerous = [];
279
- for (const pattern of DANGEROUS_PATTERNS) {
316
+ for (const pattern of patterns) {
280
317
  if (pattern.test(command)) {
281
318
  dangerous.push(pattern.source);
282
319
  }
@@ -498,4 +535,4 @@ export {
498
535
  getConfirmationSessionId,
499
536
  getPendingConfirmationsBySession
500
537
  };
501
- //# sourceMappingURL=chunk-PU3IPUSW.js.map
538
+ //# sourceMappingURL=chunk-FFPCVN5M.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createLLMClient
3
- } from "./chunk-3HS72YIE.js";
3
+ } from "./chunk-ERYUSG5C.js";
4
4
  import {
5
5
  getModelProfile
6
6
  } from "./chunk-V4IE7HJY.js";
@@ -804,4 +804,4 @@ export {
804
804
  parseDefaultModelSelection,
805
805
  createProviderManager
806
806
  };
807
- //# sourceMappingURL=chunk-KDQJOI2I.js.map
807
+ //# sourceMappingURL=chunk-FSYRANYR.js.map
@@ -0,0 +1,142 @@
1
+ import {
2
+ logger
3
+ } from "./chunk-K44MW7JJ.js";
4
+ import {
5
+ getGlobalConfigDir
6
+ } from "./chunk-CQGTEGKL.js";
7
+
8
+ // src/server/mcp/oauth-store.ts
9
+ import { chmod, mkdir, readFile, rename, writeFile } from "fs/promises";
10
+ import { dirname, join } from "path";
11
+ var storeMode = "production";
12
+ var storePathOverride;
13
+ function setMcpOAuthStoreMode(mode) {
14
+ storeMode = mode;
15
+ }
16
+ function setMcpOAuthStorePath(path) {
17
+ storePathOverride = path;
18
+ }
19
+ function getMcpOAuthStorePath() {
20
+ return storePathOverride ?? join(getGlobalConfigDir(storeMode), "mcp-auth.json");
21
+ }
22
+ async function readStore() {
23
+ const path = getMcpOAuthStorePath();
24
+ let raw;
25
+ try {
26
+ raw = await readFile(path, "utf-8");
27
+ } catch {
28
+ return { version: 1, servers: {} };
29
+ }
30
+ try {
31
+ const parsed = JSON.parse(raw);
32
+ const servers = parsed.servers;
33
+ if (!servers || typeof servers !== "object") throw new Error("no servers object");
34
+ const kept = {};
35
+ for (const [name, entry] of Object.entries(servers)) {
36
+ if (entry && typeof entry === "object" && typeof entry.serverUrl === "string") {
37
+ kept[name] = entry;
38
+ } else {
39
+ logger.warn("Dropping an unreadable MCP OAuth entry, this server will have to authorize again", {
40
+ path,
41
+ server: name
42
+ });
43
+ }
44
+ }
45
+ return { version: 1, servers: kept };
46
+ } catch {
47
+ logger.error("The MCP OAuth store is unreadable, stored authorizations will be ignored", { path });
48
+ return { version: 1, servers: {} };
49
+ }
50
+ }
51
+ async function writeStore(store) {
52
+ const path = getMcpOAuthStorePath();
53
+ await mkdir(dirname(path), { recursive: true });
54
+ const tmpPath = `${path}.tmp`;
55
+ await writeFile(tmpPath, JSON.stringify(store, null, 2), { mode: 384 });
56
+ try {
57
+ await chmod(tmpPath, 384);
58
+ } catch {
59
+ logger.warn("Could not restrict permissions on the MCP OAuth store", { path });
60
+ }
61
+ await rename(tmpPath, path);
62
+ }
63
+ var writeQueue = Promise.resolve();
64
+ function serialize(work) {
65
+ const result = writeQueue.then(work, work);
66
+ writeQueue = result.catch(() => void 0);
67
+ return result;
68
+ }
69
+ async function mutateEntry(name, serverUrl, mutate) {
70
+ await serialize(async () => {
71
+ const store = await readStore();
72
+ const current = store.servers[name];
73
+ const base = current && current.serverUrl === serverUrl ? current : { serverUrl };
74
+ store.servers[name] = mutate(base);
75
+ await writeStore(store);
76
+ });
77
+ }
78
+ function withoutAuthorizationState(entry) {
79
+ const next = { serverUrl: entry.serverUrl };
80
+ if (entry.clientInformation) next.clientInformation = entry.clientInformation;
81
+ if (entry.tokens) next.tokens = entry.tokens;
82
+ return next;
83
+ }
84
+ async function readMcpOAuthEntry(name, serverUrl) {
85
+ const store = await readStore();
86
+ const entry = store.servers[name];
87
+ if (!entry || entry.serverUrl !== serverUrl) return void 0;
88
+ return entry;
89
+ }
90
+ async function saveMcpOAuthClientInformation(name, serverUrl, clientInformation) {
91
+ await mutateEntry(name, serverUrl, (entry) => ({ ...entry, clientInformation }));
92
+ }
93
+ async function saveMcpOAuthTokens(name, serverUrl, tokens) {
94
+ await mutateEntry(name, serverUrl, (entry) => ({ ...withoutAuthorizationState(entry), tokens }));
95
+ }
96
+ async function saveMcpOAuthCodeVerifier(name, serverUrl, codeVerifier) {
97
+ await mutateEntry(name, serverUrl, (entry) => ({ ...entry, codeVerifier }));
98
+ }
99
+ async function saveMcpOAuthState(name, serverUrl, state) {
100
+ await mutateEntry(name, serverUrl, (entry) => ({ ...entry, state }));
101
+ }
102
+ async function clearMcpOAuthTokens(name, serverUrl) {
103
+ await mutateEntry(name, serverUrl, (entry) => {
104
+ const next = withoutAuthorizationState(entry);
105
+ delete next.tokens;
106
+ return next;
107
+ });
108
+ }
109
+ async function clearMcpOAuthAuthorizationState(name, serverUrl) {
110
+ await mutateEntry(name, serverUrl, withoutAuthorizationState);
111
+ }
112
+ async function clearMcpOAuthEntry(name) {
113
+ await serialize(async () => {
114
+ const store = await readStore();
115
+ if (!(name in store.servers)) return;
116
+ delete store.servers[name];
117
+ await writeStore(store);
118
+ });
119
+ }
120
+ async function findMcpOAuthEntryByState(state) {
121
+ const store = await readStore();
122
+ for (const [name, entry] of Object.entries(store.servers)) {
123
+ if (entry.state && entry.state === state) return { name, entry };
124
+ }
125
+ return null;
126
+ }
127
+
128
+ export {
129
+ setMcpOAuthStoreMode,
130
+ setMcpOAuthStorePath,
131
+ getMcpOAuthStorePath,
132
+ readMcpOAuthEntry,
133
+ saveMcpOAuthClientInformation,
134
+ saveMcpOAuthTokens,
135
+ saveMcpOAuthCodeVerifier,
136
+ saveMcpOAuthState,
137
+ clearMcpOAuthTokens,
138
+ clearMcpOAuthAuthorizationState,
139
+ clearMcpOAuthEntry,
140
+ findMcpOAuthEntryByState
141
+ };
142
+ //# sourceMappingURL=chunk-IJ53Y77N.js.map