openfox 1.6.91 → 1.6.92

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 (37) hide show
  1. package/dist/{auto-compaction-I4YS2BN4.js → auto-compaction-7AGIGW6F.js} +6 -6
  2. package/dist/{chat-handler-O4FNSVPI.js → chat-handler-UPAEF6HR.js} +9 -9
  3. package/dist/{chunk-UQSL65WB.js → chunk-2BS6LMIU.js} +398 -470
  4. package/dist/{chunk-HKCUSLQ5.js → chunk-2TKN2X2A.js} +3 -3
  5. package/dist/{chunk-SSGVISQU.js → chunk-7KO2BQFQ.js} +8 -7
  6. package/dist/{chunk-II4UCFTE.js → chunk-7QG6LY5Q.js} +3 -3
  7. package/dist/{chunk-CL2ZPJAG.js → chunk-ARJIHQ3S.js} +225 -138
  8. package/dist/{chunk-H5T34J3H.js → chunk-BHZL3N2F.js} +3 -3
  9. package/dist/{chunk-MOQLMPTA.js → chunk-CHICEUV6.js} +3 -3
  10. package/dist/{chunk-STUSQVXQ.js → chunk-RJIPM7CO.js} +2 -2
  11. package/dist/{chunk-B5AP3RSV.js → chunk-RW25DL5R.js} +3 -3
  12. package/dist/{chunk-A3YOBYWJ.js → chunk-WBQNIWAQ.js} +5 -5
  13. package/dist/{chunk-DF5BZBP6.js → chunk-XGJ7HDQ7.js} +2 -2
  14. package/dist/{chunk-6P5WQP6Y.js → chunk-YTPPQK55.js} +2 -2
  15. package/dist/cli/dev.js +1 -1
  16. package/dist/cli/index.js +1 -1
  17. package/dist/{config-GEDIDCBM.js → config-7XJQNOKX.js} +5 -5
  18. package/dist/{events-AQKDXJFK.js → events-K6AYMXFT.js} +3 -3
  19. package/dist/{orchestrator-LLOIG2CR.js → orchestrator-M4WINFF3.js} +7 -7
  20. package/dist/package.json +1 -1
  21. package/dist/{processor-XL5NULQN.js → processor-D4XQ5QMB.js} +5 -5
  22. package/dist/{protocol--8PKNwb_.d.ts → protocol-XRiJzlOK.d.ts} +1 -1
  23. package/dist/{provider-EV3KBC7Y.js → provider-UO5PAZQQ.js} +7 -7
  24. package/dist/{runtime-config-CBJJJGBD.js → runtime-config-CYHDAC7W.js} +2 -2
  25. package/dist/{serve-UWKYNKAO.js → serve-Z5FNJUDT.js} +11 -11
  26. package/dist/server/index.d.ts +1 -1
  27. package/dist/server/index.js +9 -9
  28. package/dist/shared/index.d.ts +2 -2
  29. package/dist/{tools-ZBAAAOUH.js → tools-NFFQWH6M.js} +6 -6
  30. package/dist/{vision-fallback-4TAGWGVS.js → vision-fallback-GZZWU7CR.js} +2 -2
  31. package/dist/web/assets/{index-CGEQK8Pf.css → index-CM0cLwa6.css} +1 -1
  32. package/dist/web/assets/index-SkaCnTiV.js +176 -0
  33. package/dist/web/index.html +2 -2
  34. package/dist/web/sw.js +1 -1
  35. package/package.json +1 -1
  36. package/dist/web/assets/index-Cb7XVDFv.js +0 -158
  37. /package/dist/web/{workbox-8c29f6e4.js → workbox-7fc22fbe.js} +0 -0
@@ -1,8 +1,7 @@
1
1
  import {
2
2
  SETTINGS_KEYS,
3
3
  deleteSetting,
4
- getSetting,
5
- setSetting
4
+ getSetting
6
5
  } from "./chunk-PQCFNTFJ.js";
7
6
  import {
8
7
  getProject
@@ -28,11 +27,11 @@ import {
28
27
  getBackendCapabilities,
29
28
  getModelProfile,
30
29
  streamWithSegments
31
- } from "./chunk-STUSQVXQ.js";
30
+ } from "./chunk-RJIPM7CO.js";
32
31
  import {
33
32
  getCurrentContextWindowId,
34
33
  getEventStore
35
- } from "./chunk-6P5WQP6Y.js";
34
+ } from "./chunk-YTPPQK55.js";
36
35
  import {
37
36
  buildContextMessagesFromEventHistory,
38
37
  foldContextState,
@@ -59,7 +58,7 @@ import {
59
58
  } from "./chunk-CQGTEGKL.js";
60
59
  import {
61
60
  getRuntimeConfig
62
- } from "./chunk-B5AP3RSV.js";
61
+ } from "./chunk-RW25DL5R.js";
63
62
  import {
64
63
  logger
65
64
  } from "./chunk-K44MW7JJ.js";
@@ -1058,28 +1057,105 @@ Error: ${toolResult.error}` : `Error: ${toolResult.error}`;
1058
1057
  }
1059
1058
 
1060
1059
  // src/server/agents/registry.ts
1061
- import { readdir, readFile as readFile2, writeFile, mkdir, access as access2, unlink } from "fs/promises";
1062
- import { join as join2, dirname as dirname2 } from "path";
1063
- import { constants as constants2 } from "fs";
1060
+ import { readdir as readdir2, readFile as readFile3, writeFile as writeFile2, mkdir as mkdir2, access as access3, unlink as unlink2 } from "fs/promises";
1061
+ import { join as join3, dirname as dirname2 } from "path";
1062
+ import { constants as constants3 } from "fs";
1064
1063
  import { fileURLToPath } from "url";
1064
+ import matter2 from "gray-matter";
1065
+
1066
+ // src/server/shared/item-loader.ts
1067
+ import { readdir, readFile as readFile2, access as access2, writeFile, mkdir, unlink } from "fs/promises";
1068
+ import { join as join2 } from "path";
1069
+ import { constants as constants2 } from "fs";
1065
1070
  import matter from "gray-matter";
1071
+ async function pathExists(path) {
1072
+ try {
1073
+ await access2(path, constants2.R_OK);
1074
+ return true;
1075
+ } catch {
1076
+ return false;
1077
+ }
1078
+ }
1079
+ async function getDefaultIds(dir, extension) {
1080
+ try {
1081
+ const files = (await readdir(dir)).filter((f) => f.endsWith(extension));
1082
+ return files.map((f) => f.replace(extension, ""));
1083
+ } catch {
1084
+ return [];
1085
+ }
1086
+ }
1087
+ async function loadItemsFromDir(dir, options) {
1088
+ if (!await pathExists(dir)) {
1089
+ return [];
1090
+ }
1091
+ let files;
1092
+ try {
1093
+ files = (await readdir(dir)).filter((f) => f.endsWith(options.extension));
1094
+ } catch {
1095
+ return [];
1096
+ }
1097
+ const items = [];
1098
+ for (const file of files) {
1099
+ try {
1100
+ const raw = await readFile2(join2(dir, file), "utf-8");
1101
+ const { data, content } = matter(raw);
1102
+ if (data.id && content.trim()) {
1103
+ items.push({
1104
+ metadata: data,
1105
+ prompt: content.trim()
1106
+ });
1107
+ } else {
1108
+ logger.warn(`Skipping invalid ${options.logName} file`, { file });
1109
+ }
1110
+ } catch (err) {
1111
+ logger.warn(`Failed to parse ${options.logName} file`, {
1112
+ file,
1113
+ error: err instanceof Error ? err.message : String(err)
1114
+ });
1115
+ }
1116
+ }
1117
+ return items;
1118
+ }
1119
+ async function saveItemToDir(dir, item, ext, serialize) {
1120
+ if (!await pathExists(dir)) {
1121
+ await mkdir(dir, { recursive: true });
1122
+ }
1123
+ const meta = item.metadata;
1124
+ const filePath = join2(dir, `${meta.id}${ext}`);
1125
+ await writeFile(filePath, serialize(item), "utf-8");
1126
+ }
1127
+ var jsonSerializer = (item) => JSON.stringify(item, null, 2) + "\n";
1128
+ async function deleteItemFromDir(dir, id, ext) {
1129
+ const filePath = join2(dir, `${id}${ext}`);
1130
+ try {
1131
+ await unlink(filePath);
1132
+ return { success: true };
1133
+ } catch {
1134
+ return { success: false };
1135
+ }
1136
+ }
1137
+
1138
+ // src/server/agents/registry.ts
1066
1139
  var __bundleDir = dirname2(fileURLToPath(import.meta.url));
1067
- var DEFAULTS_DIR = join2(__bundleDir, "defaults");
1068
- var DEFAULTS_DIR_ALT = join2(__bundleDir, "agent-defaults");
1140
+ var DEFAULTS_DIR = join3(__bundleDir, "defaults");
1141
+ var DEFAULTS_DIR_ALT = join3(__bundleDir, "agent-defaults");
1069
1142
  var AGENT_EXTENSION = ".agent.md";
1070
1143
  function getAgentsDir(configDir) {
1071
- return join2(configDir, "agents");
1144
+ return join3(configDir, "agents");
1072
1145
  }
1073
- async function pathExists(path) {
1146
+ function getProjectAgentsDir(projectDir) {
1147
+ return join3(projectDir, ".openfox", "agents");
1148
+ }
1149
+ async function pathExists2(path) {
1074
1150
  try {
1075
- await access2(path, constants2.R_OK);
1151
+ await access3(path, constants3.R_OK);
1076
1152
  return true;
1077
1153
  } catch {
1078
1154
  return false;
1079
1155
  }
1080
1156
  }
1081
1157
  function parseAgentFile(raw, filename) {
1082
- const { data, content } = matter(raw);
1158
+ const { data, content } = matter2(raw);
1083
1159
  const meta = data;
1084
1160
  if (!meta["id"] || !content.trim()) {
1085
1161
  logger.warn("Skipping invalid agent file", { filename });
@@ -1097,19 +1173,19 @@ function parseAgentFile(raw, filename) {
1097
1173
  return { metadata, prompt: content.trim() };
1098
1174
  }
1099
1175
  async function loadAgentsFromDir(dir) {
1100
- if (!await pathExists(dir)) {
1176
+ if (!await pathExists2(dir)) {
1101
1177
  return [];
1102
1178
  }
1103
1179
  let files;
1104
1180
  try {
1105
- files = (await readdir(dir)).filter((f) => f.endsWith(AGENT_EXTENSION));
1181
+ files = (await readdir2(dir)).filter((f) => f.endsWith(AGENT_EXTENSION));
1106
1182
  } catch {
1107
1183
  return [];
1108
1184
  }
1109
1185
  const agents = [];
1110
1186
  for (const file of files) {
1111
1187
  try {
1112
- const raw = await readFile2(join2(dir, file), "utf-8");
1188
+ const raw = await readFile3(join3(dir, file), "utf-8");
1113
1189
  const agent = parseAgentFile(raw, file);
1114
1190
  if (agent) {
1115
1191
  agents.push(agent);
@@ -1128,7 +1204,10 @@ async function loadDefaultAgents() {
1128
1204
  async function loadUserAgents(configDir) {
1129
1205
  return loadAgentsFromDir(getAgentsDir(configDir));
1130
1206
  }
1131
- async function loadAllAgents(configDir) {
1207
+ async function loadProjectAgents(projectDir) {
1208
+ return loadAgentsFromDir(getProjectAgentsDir(projectDir));
1209
+ }
1210
+ async function loadAllAgents(configDir, projectDir) {
1132
1211
  const [defaultAgents, userAgents] = await Promise.all([loadDefaultAgents(), loadUserAgents(configDir)]);
1133
1212
  const agentMap = /* @__PURE__ */ new Map();
1134
1213
  for (const agent of defaultAgents) {
@@ -1137,12 +1216,40 @@ async function loadAllAgents(configDir) {
1137
1216
  for (const agent of userAgents) {
1138
1217
  agentMap.set(agent.metadata.id, agent);
1139
1218
  }
1219
+ if (projectDir) {
1220
+ const projectAgents = await loadProjectAgents(projectDir);
1221
+ for (const agent of projectAgents) {
1222
+ agentMap.set(agent.metadata.id, agent);
1223
+ }
1224
+ }
1140
1225
  return Array.from(agentMap.values());
1141
1226
  }
1227
+ async function saveAgentToProject(projectDir, agent) {
1228
+ await saveItemToDir(
1229
+ getProjectAgentsDir(projectDir),
1230
+ agent,
1231
+ AGENT_EXTENSION,
1232
+ (a) => matter2.stringify(a.prompt, a.metadata)
1233
+ );
1234
+ }
1235
+ async function deleteProjectAgent(projectDir, agentId) {
1236
+ const agentsDir = getProjectAgentsDir(projectDir);
1237
+ const paths = getAgentFilePaths(agentsDir, agentId);
1238
+ for (const filePath of paths) {
1239
+ try {
1240
+ await unlink2(filePath);
1241
+ return { success: true };
1242
+ } catch {
1243
+ continue;
1244
+ }
1245
+ }
1246
+ return { success: false };
1247
+ }
1142
1248
  async function loadAllAgentsDefault() {
1143
1249
  try {
1144
- const configDir = getGlobalConfigDir(getRuntimeConfig().mode ?? "production");
1145
- return await loadAllAgents(configDir);
1250
+ const config = getRuntimeConfig();
1251
+ const configDir = getGlobalConfigDir(config.mode ?? "production");
1252
+ return await loadAllAgents(configDir, config.workdir);
1146
1253
  } catch {
1147
1254
  return loadDefaultAgents();
1148
1255
  }
@@ -1150,24 +1257,20 @@ async function loadAllAgentsDefault() {
1150
1257
  async function getDefaultAgentIds() {
1151
1258
  for (const dir of [DEFAULTS_DIR, DEFAULTS_DIR_ALT]) {
1152
1259
  try {
1153
- const files = (await readdir(dir)).filter((f) => f.endsWith(AGENT_EXTENSION));
1260
+ const files = (await readdir2(dir)).filter((f) => f.endsWith(AGENT_EXTENSION));
1154
1261
  return files.map((f) => f.replace(AGENT_EXTENSION, ""));
1155
1262
  } catch {
1156
1263
  }
1157
1264
  }
1158
1265
  return [];
1159
1266
  }
1160
- async function getDefaultAgentContent(agentId) {
1161
- const defaults = await loadDefaultAgents();
1162
- return defaults.find((a) => a.metadata.id === agentId) ?? null;
1163
- }
1164
1267
  async function isDefaultAgent(agentId) {
1165
1268
  const defaultIds = await getDefaultAgentIds();
1166
1269
  return defaultIds.includes(agentId);
1167
1270
  }
1168
1271
  function getAgentFilePaths(agentsDir, agentId) {
1169
1272
  const hyphenated = agentId.replace(/_/g, "-");
1170
- return [join2(agentsDir, `${agentId}${AGENT_EXTENSION}`), join2(agentsDir, `${hyphenated}${AGENT_EXTENSION}`)];
1273
+ return [join3(agentsDir, `${agentId}${AGENT_EXTENSION}`), join3(agentsDir, `${hyphenated}${AGENT_EXTENSION}`)];
1171
1274
  }
1172
1275
  function findAgentById(agentId, agents) {
1173
1276
  return agents.find((a) => a.metadata.id === agentId);
@@ -1178,24 +1281,32 @@ function getSubAgents(agents) {
1178
1281
  function getTopLevelAgents(agents) {
1179
1282
  return agents.filter((a) => !a.metadata.subagent);
1180
1283
  }
1181
- async function agentExists(configDir, agentId) {
1284
+ async function agentExists(configDir, agentId, projectDir) {
1182
1285
  const agentsDir = getAgentsDir(configDir);
1183
1286
  const paths = getAgentFilePaths(agentsDir, agentId);
1184
1287
  for (const filePath of paths) {
1185
- if (await pathExists(filePath)) {
1288
+ if (await pathExists2(filePath)) {
1186
1289
  return true;
1187
1290
  }
1188
1291
  }
1292
+ if (projectDir) {
1293
+ const projectPaths = getAgentFilePaths(getProjectAgentsDir(projectDir), agentId);
1294
+ for (const filePath of projectPaths) {
1295
+ if (await pathExists2(filePath)) {
1296
+ return true;
1297
+ }
1298
+ }
1299
+ }
1189
1300
  return false;
1190
1301
  }
1191
1302
  async function saveAgent(configDir, agent) {
1192
1303
  const agentsDir = getAgentsDir(configDir);
1193
- if (!await pathExists(agentsDir)) {
1194
- await mkdir(agentsDir, { recursive: true });
1304
+ if (!await pathExists2(agentsDir)) {
1305
+ await mkdir2(agentsDir, { recursive: true });
1195
1306
  }
1196
- const filePath = join2(agentsDir, `${agent.metadata.id}${AGENT_EXTENSION}`);
1197
- const content = matter.stringify(agent.prompt, agent.metadata);
1198
- await writeFile(filePath, content, "utf-8");
1307
+ const filePath = join3(agentsDir, `${agent.metadata.id}${AGENT_EXTENSION}`);
1308
+ const content = matter2.stringify(agent.prompt, agent.metadata);
1309
+ await writeFile2(filePath, content, "utf-8");
1199
1310
  }
1200
1311
  async function deleteAgent(configDir, agentId) {
1201
1312
  const isDefault = await isDefaultAgent(agentId);
@@ -1206,7 +1317,7 @@ async function deleteAgent(configDir, agentId) {
1206
1317
  const paths = getAgentFilePaths(agentsDir, agentId);
1207
1318
  for (const filePath of paths) {
1208
1319
  try {
1209
- await unlink(filePath);
1320
+ await unlink2(filePath);
1210
1321
  return { success: true };
1211
1322
  } catch {
1212
1323
  continue;
@@ -1216,7 +1327,7 @@ async function deleteAgent(configDir, agentId) {
1216
1327
  }
1217
1328
 
1218
1329
  // src/server/tools/read.ts
1219
- import { readFile as readFile4, stat } from "fs/promises";
1330
+ import { readFile as readFile5, stat } from "fs/promises";
1220
1331
  import { extname } from "path";
1221
1332
 
1222
1333
  // src/server/tools/types.ts
@@ -1247,7 +1358,7 @@ import { resolve as resolve2, isAbsolute } from "path";
1247
1358
 
1248
1359
  // src/server/tools/path-security.ts
1249
1360
  import { realpath } from "fs/promises";
1250
- import { resolve, normalize, join as join3, basename, sep } from "path";
1361
+ import { resolve, normalize, join as join4, basename, sep } from "path";
1251
1362
  import { homedir, tmpdir } from "os";
1252
1363
  var SAFE_PATHS = /* @__PURE__ */ new Set([
1253
1364
  "/dev/null",
@@ -1381,7 +1492,7 @@ function extractAbsolutePathsFromCommand(command) {
1381
1492
  }
1382
1493
  } else if (content.startsWith("~")) {
1383
1494
  const pathPart = content.slice(1);
1384
- const fullPath = join3(home, pathPart);
1495
+ const fullPath = join4(home, pathPart);
1385
1496
  const resolved = normalize(resolve(fullPath));
1386
1497
  if (!isSafePath(resolved)) {
1387
1498
  paths.push(resolved);
@@ -1691,7 +1802,7 @@ function createTool(name, definition, handler2) {
1691
1802
 
1692
1803
  // src/server/tools/file-tracker.ts
1693
1804
  import { createHash } from "crypto";
1694
- import { readFile as readFile3 } from "fs/promises";
1805
+ import { readFile as readFile4 } from "fs/promises";
1695
1806
  import { resolve as resolve3 } from "path";
1696
1807
  var FileNotReadError = class extends Error {
1697
1808
  constructor(path) {
@@ -1709,7 +1820,7 @@ var FileChangedExternallyError = class extends Error {
1709
1820
  };
1710
1821
  async function computeFileHash(filePath) {
1711
1822
  try {
1712
- const content = await readFile3(filePath);
1823
+ const content = await readFile4(filePath);
1713
1824
  const hash = createHash("sha256");
1714
1825
  hash.update(content);
1715
1826
  return hash.digest("hex");
@@ -1844,7 +1955,7 @@ var readFileTool = createTool(
1844
1955
  } catch {
1845
1956
  return helpers.error(`File not found: ${args.path}`);
1846
1957
  }
1847
- const rawBuffer = await readFile4(fullPath);
1958
+ const rawBuffer = await readFile5(fullPath);
1848
1959
  const mimeType = detectImageType(rawBuffer, args.path);
1849
1960
  if (mimeType) {
1850
1961
  const base64Data = rawBuffer.toString("base64");
@@ -1890,7 +2001,7 @@ var readFileTool = createTool(
1890
2001
  );
1891
2002
 
1892
2003
  // src/server/tools/write.ts
1893
- import { writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
2004
+ import { writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
1894
2005
  import { dirname as dirname3 } from "path";
1895
2006
 
1896
2007
  // src/server/tools/diagnostics.ts
@@ -1951,8 +2062,8 @@ var writeFileTool = createTool(
1951
2062
  return helpers.error(validation.error?.message ?? "File validation failed");
1952
2063
  }
1953
2064
  const dir = dirname3(fullPath);
1954
- await mkdir2(dir, { recursive: true });
1955
- await writeFile2(fullPath, args.content, "utf-8");
2065
+ await mkdir3(dir, { recursive: true });
2066
+ await writeFile3(fullPath, args.content, "utf-8");
1956
2067
  const lineCount = args.content.split("\n").length;
1957
2068
  const byteCount = Buffer.byteLength(args.content, "utf-8");
1958
2069
  let output = `Successfully wrote ${lineCount} lines (${byteCount} bytes) to ${args.path}`;
@@ -1970,7 +2081,7 @@ var writeFileTool = createTool(
1970
2081
  );
1971
2082
 
1972
2083
  // src/server/tools/edit.ts
1973
- import { readFile as readFile5, writeFile as writeFile3 } from "fs/promises";
2084
+ import { readFile as readFile6, writeFile as writeFile4 } from "fs/promises";
1974
2085
 
1975
2086
  // src/server/tools/edit-context.ts
1976
2087
  var CONTEXT_LINES = 4;
@@ -2126,7 +2237,7 @@ var editFileTool = createTool(
2126
2237
  }
2127
2238
  let content;
2128
2239
  try {
2129
- content = await readFile5(fullPath, "utf-8");
2240
+ content = await readFile6(fullPath, "utf-8");
2130
2241
  } catch {
2131
2242
  return helpers.error(`File not found: ${args.path}`);
2132
2243
  }
@@ -2191,7 +2302,7 @@ Make sure whitespace and indentation match exactly.`
2191
2302
  /\n/g,
2192
2303
  fileLineEnding === "crlf" ? "\r\n" : fileLineEnding === "cr" ? "\r" : "\n"
2193
2304
  );
2194
- await writeFile3(fullPath, newContent, "utf-8");
2305
+ await writeFile4(fullPath, newContent, "utf-8");
2195
2306
  let output = `Successfully replaced ${replaceAll ? occurrences : 1} occurrence(s) in ${args.path}`;
2196
2307
  let diagnostics = [];
2197
2308
  if (context.lspManager) {
@@ -2692,66 +2803,10 @@ function createToolProgressHandler(eventStore, messageId, callId, sessionId) {
2692
2803
  }
2693
2804
 
2694
2805
  // src/server/skills/registry.ts
2695
- import { writeFile as writeFile4, mkdir as mkdir3, unlink as unlink2 } from "fs/promises";
2806
+ import { writeFile as writeFile5, mkdir as mkdir4, unlink as unlink3 } from "fs/promises";
2696
2807
  import { join as join5, dirname as dirname4 } from "path";
2697
2808
  import { fileURLToPath as fileURLToPath2 } from "url";
2698
2809
  import matter3 from "gray-matter";
2699
-
2700
- // src/server/shared/item-loader.ts
2701
- import { readdir as readdir2, readFile as readFile6, access as access3 } from "fs/promises";
2702
- import { join as join4 } from "path";
2703
- import { constants as constants3 } from "fs";
2704
- import matter2 from "gray-matter";
2705
- async function pathExists2(path) {
2706
- try {
2707
- await access3(path, constants3.R_OK);
2708
- return true;
2709
- } catch {
2710
- return false;
2711
- }
2712
- }
2713
- async function getDefaultIds(dir, extension) {
2714
- try {
2715
- const files = (await readdir2(dir)).filter((f) => f.endsWith(extension));
2716
- return files.map((f) => f.replace(extension, ""));
2717
- } catch {
2718
- return [];
2719
- }
2720
- }
2721
- async function loadItemsFromDir(dir, options) {
2722
- if (!await pathExists2(dir)) {
2723
- return [];
2724
- }
2725
- let files;
2726
- try {
2727
- files = (await readdir2(dir)).filter((f) => f.endsWith(options.extension));
2728
- } catch {
2729
- return [];
2730
- }
2731
- const items = [];
2732
- for (const file of files) {
2733
- try {
2734
- const raw = await readFile6(join4(dir, file), "utf-8");
2735
- const { data, content } = matter2(raw);
2736
- if (data.id && content.trim()) {
2737
- items.push({
2738
- metadata: data,
2739
- prompt: content.trim()
2740
- });
2741
- } else {
2742
- logger.warn(`Skipping invalid ${options.logName} file`, { file });
2743
- }
2744
- } catch (err) {
2745
- logger.warn(`Failed to parse ${options.logName} file`, {
2746
- file,
2747
- error: err instanceof Error ? err.message : String(err)
2748
- });
2749
- }
2750
- }
2751
- return items;
2752
- }
2753
-
2754
- // src/server/skills/registry.ts
2755
2810
  var __bundleDir2 = dirname4(fileURLToPath2(import.meta.url));
2756
2811
  var DEFAULTS_DIR2 = join5(__bundleDir2, "defaults");
2757
2812
  var DEFAULTS_DIR_ALT2 = join5(__bundleDir2, "skill-defaults");
@@ -2760,6 +2815,9 @@ var SKILL_SETTING_PREFIX = "skill.enabled.";
2760
2815
  function getSkillsDir(configDir) {
2761
2816
  return join5(configDir, "skills");
2762
2817
  }
2818
+ function getProjectSkillsDir(projectDir) {
2819
+ return join5(projectDir, ".openfox", "skills");
2820
+ }
2763
2821
  async function loadDefaultSkills() {
2764
2822
  let defaults = await loadItemsFromDir(DEFAULTS_DIR2, {
2765
2823
  extension: SKILL_EXTENSION,
@@ -2779,7 +2837,13 @@ async function loadUserSkills(configDir) {
2779
2837
  logName: "skill"
2780
2838
  });
2781
2839
  }
2782
- async function loadAllSkills(configDir) {
2840
+ async function loadProjectSkills(projectDir) {
2841
+ return loadItemsFromDir(getProjectSkillsDir(projectDir), {
2842
+ extension: SKILL_EXTENSION,
2843
+ logName: "skill"
2844
+ });
2845
+ }
2846
+ async function loadAllSkills(configDir, projectDir) {
2783
2847
  const [defaultSkills, userSkills] = await Promise.all([loadDefaultSkills(), loadUserSkills(configDir)]);
2784
2848
  const skillMap = /* @__PURE__ */ new Map();
2785
2849
  for (const skill of defaultSkills) {
@@ -2788,14 +2852,20 @@ async function loadAllSkills(configDir) {
2788
2852
  for (const skill of userSkills) {
2789
2853
  skillMap.set(skill.metadata.id, skill);
2790
2854
  }
2855
+ if (projectDir) {
2856
+ const projectSkills = await loadProjectSkills(projectDir);
2857
+ for (const skill of projectSkills) {
2858
+ skillMap.set(skill.metadata.id, skill);
2859
+ }
2860
+ }
2791
2861
  return Array.from(skillMap.values());
2792
2862
  }
2793
- async function getEnabledSkills(configDir) {
2794
- const all = await loadAllSkills(configDir);
2863
+ async function getEnabledSkills(configDir, projectDir) {
2864
+ const all = await loadAllSkills(configDir, projectDir);
2795
2865
  return all.filter((s) => isSkillEnabled(s.metadata.id));
2796
2866
  }
2797
- async function getEnabledSkillMetadata(configDir) {
2798
- const enabled = await getEnabledSkills(configDir);
2867
+ async function getEnabledSkillMetadata(configDir, projectDir) {
2868
+ const enabled = await getEnabledSkills(configDir, projectDir);
2799
2869
  return enabled.map((s) => s.metadata);
2800
2870
  }
2801
2871
  function isSkillEnabled(skillId) {
@@ -2803,18 +2873,11 @@ function isSkillEnabled(skillId) {
2803
2873
  if (value === null) return true;
2804
2874
  return value === "true";
2805
2875
  }
2806
- function setSkillEnabled(skillId, enabled) {
2807
- setSetting(`${SKILL_SETTING_PREFIX}${skillId}`, String(enabled));
2808
- }
2809
2876
  async function getDefaultSkillIds() {
2810
2877
  const ids = await getDefaultIds(DEFAULTS_DIR2, SKILL_EXTENSION);
2811
2878
  if (ids.length) return ids;
2812
2879
  return getDefaultIds(DEFAULTS_DIR_ALT2, SKILL_EXTENSION);
2813
2880
  }
2814
- async function getDefaultSkillContent(skillId) {
2815
- const defaults = await loadDefaultSkills();
2816
- return defaults.find((s) => s.metadata.id === skillId) ?? null;
2817
- }
2818
2881
  async function isDefaultSkill(skillId) {
2819
2882
  const defaultIds = await getDefaultSkillIds();
2820
2883
  return defaultIds.includes(skillId);
@@ -2822,17 +2885,28 @@ async function isDefaultSkill(skillId) {
2822
2885
  function findSkillById(skillId, skills) {
2823
2886
  return skills.find((s) => s.metadata.id === skillId);
2824
2887
  }
2825
- async function skillExists(configDir, skillId) {
2826
- return pathExists2(join5(getSkillsDir(configDir), `${skillId}${SKILL_EXTENSION}`));
2888
+ async function skillExists(configDir, skillId, projectDir) {
2889
+ if (await pathExists(join5(getSkillsDir(configDir), `${skillId}${SKILL_EXTENSION}`))) return true;
2890
+ if (projectDir && await pathExists(join5(getProjectSkillsDir(projectDir), `${skillId}${SKILL_EXTENSION}`)))
2891
+ return true;
2892
+ return false;
2827
2893
  }
2828
2894
  async function saveSkill(configDir, skill) {
2829
2895
  const skillsDir = getSkillsDir(configDir);
2830
- if (!await pathExists2(skillsDir)) {
2831
- await mkdir3(skillsDir, { recursive: true });
2896
+ if (!await pathExists(skillsDir)) {
2897
+ await mkdir4(skillsDir, { recursive: true });
2832
2898
  }
2833
2899
  const filePath = join5(skillsDir, `${skill.metadata.id}${SKILL_EXTENSION}`);
2834
2900
  const content = matter3.stringify(skill.prompt, skill.metadata);
2835
- await writeFile4(filePath, content, "utf-8");
2901
+ await writeFile5(filePath, content, "utf-8");
2902
+ }
2903
+ async function saveSkillToProject(projectDir, skill) {
2904
+ await saveItemToDir(
2905
+ getProjectSkillsDir(projectDir),
2906
+ skill,
2907
+ SKILL_EXTENSION,
2908
+ (s) => matter3.stringify(s.prompt, s.metadata)
2909
+ );
2836
2910
  }
2837
2911
  async function deleteSkill(configDir, skillId) {
2838
2912
  const isDefault = await isDefaultSkill(skillId);
@@ -2841,13 +2915,16 @@ async function deleteSkill(configDir, skillId) {
2841
2915
  }
2842
2916
  const filePath = join5(getSkillsDir(configDir), `${skillId}${SKILL_EXTENSION}`);
2843
2917
  try {
2844
- await unlink2(filePath);
2918
+ await unlink3(filePath);
2845
2919
  deleteSetting(`${SKILL_SETTING_PREFIX}${skillId}`);
2846
2920
  return { success: true };
2847
2921
  } catch {
2848
2922
  return { success: false };
2849
2923
  }
2850
2924
  }
2925
+ async function deleteProjectSkill(projectDir, skillId) {
2926
+ return deleteItemFromDir(getProjectSkillsDir(projectDir), skillId, SKILL_EXTENSION);
2927
+ }
2851
2928
 
2852
2929
  // src/server/chat/agent-loop.ts
2853
2930
  import stripAnsi from "strip-ansi";
@@ -3141,8 +3218,9 @@ async function runTopLevelAgentLoop(config, turnMetrics) {
3141
3218
  eventStore.append(sessionId, createFormatRetryEvent(formatRetryCount, MAX_FORMAT_RETRIES));
3142
3219
  requestMessages.push({ role: "user", content: FORMAT_CORRECTION_PROMPT2, source: "history" });
3143
3220
  }
3144
- const configDir = getGlobalConfigDir(getRuntimeConfig().mode ?? "production");
3145
- const skills = await getEnabledSkillMetadata(configDir);
3221
+ const runtimeConfig = getRuntimeConfig();
3222
+ const configDir = getGlobalConfigDir(runtimeConfig.mode ?? "production");
3223
+ const skills = await getEnabledSkillMetadata(configDir, runtimeConfig.workdir);
3146
3224
  if (signal?.aborted) throw new Error("Aborted");
3147
3225
  const assembledRequest = config.assembleRequest({
3148
3226
  workdir: session.workdir,
@@ -3532,8 +3610,9 @@ async function executeSubAgent(options) {
3532
3610
  }
3533
3611
  const { content: instructionContent, files } = await getAllInstructions(session.workdir, session.projectId);
3534
3612
  const injectedFiles = toInjectedFiles(files);
3535
- const configDir = getGlobalConfigDir(getRuntimeConfig().mode ?? "production");
3536
- const skills = await getEnabledSkillMetadata(configDir);
3613
+ const config = getRuntimeConfig();
3614
+ const configDir = getGlobalConfigDir(config.mode ?? "production");
3615
+ const skills = await getEnabledSkillMetadata(configDir, config.workdir);
3537
3616
  const systemPrompt = buildSubAgentSystemPrompt(
3538
3617
  session.workdir,
3539
3618
  agentDef,
@@ -3802,7 +3881,7 @@ var callSubAgentTool = {
3802
3881
  };
3803
3882
  }
3804
3883
  try {
3805
- const { getToolRegistryForAgent: getToolRegistryForAgent2 } = await import("./tools-ZBAAAOUH.js");
3884
+ const { getToolRegistryForAgent: getToolRegistryForAgent2 } = await import("./tools-NFFQWH6M.js");
3806
3885
  const toolRegistry = getToolRegistryForAgent2(agentDef);
3807
3886
  const turnMetrics = new TurnMetrics();
3808
3887
  const result = await executeSubAgent({
@@ -3850,7 +3929,7 @@ var handler = async (args, _context, helpers) => {
3850
3929
  }
3851
3930
  const config = getRuntimeConfig();
3852
3931
  const configDir = getGlobalConfigDir(config.mode ?? "production");
3853
- const allSkills = await loadAllSkills(configDir);
3932
+ const allSkills = await loadAllSkills(configDir, config.workdir);
3854
3933
  const skill = findSkillById(skillId, allSkills);
3855
3934
  if (!skill) {
3856
3935
  const available = allSkills.map((s) => s.metadata.id).join(", ");
@@ -4054,7 +4133,7 @@ var webFetchTool = createTool(
4054
4133
 
4055
4134
  // src/server/dev-server/manager.ts
4056
4135
  import { spawn as spawn3 } from "child_process";
4057
- import { readFile as readFile7, writeFile as writeFile5, mkdir as mkdir4 } from "fs/promises";
4136
+ import { readFile as readFile7, writeFile as writeFile6, mkdir as mkdir5 } from "fs/promises";
4058
4137
  import { resolve as resolve5, join as join6 } from "path";
4059
4138
  var MAX_LOG_LINES = 2e3;
4060
4139
  var MAX_LOG_BYTES = 1e5;
@@ -4137,9 +4216,9 @@ var DevServerManager = class {
4137
4216
  async saveConfig(workdir, config) {
4138
4217
  const resolved = this.resolveWorkdir(workdir);
4139
4218
  const dirPath = join6(resolved, ".openfox");
4140
- await mkdir4(dirPath, { recursive: true });
4219
+ await mkdir5(dirPath, { recursive: true });
4141
4220
  const configPath = getDevServerConfigPath(workdir);
4142
- await writeFile5(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
4221
+ await writeFile6(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
4143
4222
  }
4144
4223
  async start(workdir) {
4145
4224
  const instance = this.getInstance(workdir);
@@ -4839,7 +4918,7 @@ async function performContextCompaction(options) {
4839
4918
  const subAgentDefs = getSubAgents(allAgents);
4840
4919
  const toolRegistry = getToolRegistryForAgent(plannerDef);
4841
4920
  const configDir = getGlobalConfigDir(config.mode ?? "production");
4842
- const skills = await getEnabledSkillMetadata(configDir);
4921
+ const skills = await getEnabledSkillMetadata(configDir, config.workdir);
4843
4922
  const assembledRequest = assembleAgentRequest({
4844
4923
  agentDef: plannerDef,
4845
4924
  subAgentDefs,
@@ -4942,12 +5021,21 @@ export {
4942
5021
  cancelPathConfirmationsForSession,
4943
5022
  checkAborted,
4944
5023
  spawnShellProcess,
5024
+ pathExists,
5025
+ getDefaultIds,
5026
+ loadItemsFromDir,
5027
+ saveItemToDir,
5028
+ jsonSerializer,
5029
+ deleteItemFromDir,
4945
5030
  loadDefaultAgents,
4946
5031
  loadUserAgents,
5032
+ loadProjectAgents,
4947
5033
  loadAllAgents,
5034
+ saveAgentToProject,
5035
+ deleteProjectAgent,
4948
5036
  loadAllAgentsDefault,
4949
5037
  getDefaultAgentIds,
4950
- getDefaultAgentContent,
5038
+ isDefaultAgent,
4951
5039
  findAgentById,
4952
5040
  getSubAgents,
4953
5041
  getTopLevelAgents,
@@ -4964,20 +5052,19 @@ export {
4964
5052
  createToolResultEvent,
4965
5053
  createChatDoneEvent,
4966
5054
  assembleAgentRequest,
4967
- pathExists2 as pathExists,
4968
- getDefaultIds,
4969
- loadItemsFromDir,
4970
5055
  loadDefaultSkills,
4971
5056
  loadUserSkills,
5057
+ loadProjectSkills,
4972
5058
  loadAllSkills,
4973
5059
  isSkillEnabled,
4974
- setSkillEnabled,
4975
5060
  getDefaultSkillIds,
4976
- getDefaultSkillContent,
5061
+ isDefaultSkill,
4977
5062
  findSkillById,
4978
5063
  skillExists,
4979
5064
  saveSkill,
5065
+ saveSkillToProject,
4980
5066
  deleteSkill,
5067
+ deleteProjectSkill,
4981
5068
  maybeAutoCompactContext,
4982
5069
  performManualContextCompaction,
4983
5070
  resolveCompactionStatsIdentity,
@@ -4993,4 +5080,4 @@ export {
4993
5080
  getToolRegistryForAgent,
4994
5081
  createToolRegistry
4995
5082
  };
4996
- //# sourceMappingURL=chunk-CL2ZPJAG.js.map
5083
+ //# sourceMappingURL=chunk-ARJIHQ3S.js.map