zephex 2.0.16 → 2.1.0

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.
@@ -150,21 +150,107 @@ function filePolyfill(path) {
150
150
  text: async () => readFile(path, "utf8")
151
151
  };
152
152
  }
153
+ function globToRegExp(pattern) {
154
+ let re = "";
155
+ let i = 0;
156
+ while (i < pattern.length) {
157
+ const c = pattern[i];
158
+ if (c === "*") {
159
+ if (pattern[i + 1] === "*") {
160
+ if (pattern[i + 2] === "/") {
161
+ re += "(?:.*/)?";
162
+ i += 3;
163
+ continue;
164
+ }
165
+ re += ".*";
166
+ i += 2;
167
+ continue;
168
+ }
169
+ re += "[^/]*";
170
+ i++;
171
+ continue;
172
+ }
173
+ if (c === "?") {
174
+ re += "[^/]";
175
+ i++;
176
+ continue;
177
+ }
178
+ if (c === "{") {
179
+ const close = pattern.indexOf("}", i);
180
+ if (close > i) {
181
+ const parts = pattern.slice(i + 1, close).split(",").map((s) => s.replace(/[.+^${}()|[\]\\]/g, "\\$&"));
182
+ re += "(?:" + parts.join("|") + ")";
183
+ i = close + 1;
184
+ continue;
185
+ }
186
+ }
187
+ if (/[.+^${}()|[\]\\]/.test(c)) {
188
+ re += "\\" + c;
189
+ } else {
190
+ re += c;
191
+ }
192
+ i++;
193
+ }
194
+ return new RegExp("^" + re + "$");
195
+ }
153
196
 
154
197
  class GlobPolyfill {
155
198
  pattern;
199
+ regex;
156
200
  constructor(pattern) {
157
201
  this.pattern = pattern;
202
+ this.regex = globToRegExp(pattern);
158
203
  }
159
204
  async* scan(opts) {
160
- const { glob } = await import("node:fs/promises");
161
- const cwd = opts?.cwd ?? process.cwd();
162
- for await (const entry of glob(this.pattern, { cwd })) {
163
- if (opts?.absolute) {
164
- const { resolve } = await import("node:path");
165
- yield resolve(cwd, entry);
166
- } else {
167
- yield entry;
205
+ const cwd = (typeof opts === "string" ? opts : opts?.cwd) ?? process.cwd();
206
+ const absolute = typeof opts === "string" ? false : opts?.absolute ?? false;
207
+ const { readdir } = await import("node:fs/promises");
208
+ const { resolve, sep } = await import("node:path");
209
+ const SKIP = new Set([
210
+ "node_modules",
211
+ ".git",
212
+ ".next",
213
+ ".turbo",
214
+ ".cache",
215
+ "dist",
216
+ "build",
217
+ "out",
218
+ "coverage",
219
+ "__pycache__",
220
+ ".venv",
221
+ "venv",
222
+ "target",
223
+ ".idea",
224
+ ".vscode"
225
+ ]);
226
+ let entries;
227
+ try {
228
+ entries = await readdir(cwd, {
229
+ recursive: true,
230
+ withFileTypes: true
231
+ });
232
+ } catch {
233
+ return;
234
+ }
235
+ for (const ent of entries) {
236
+ if (typeof ent.isFile === "function" && !ent.isFile())
237
+ continue;
238
+ const parent = ent.parentPath ?? ent.path ?? cwd;
239
+ const fullPath = parent.endsWith(sep) ? parent + ent.name : parent + sep + ent.name;
240
+ let rel = fullPath.startsWith(cwd) ? fullPath.slice(cwd.length).replace(/^[\\/]+/, "") : fullPath;
241
+ rel = rel.split(sep).join("/");
242
+ const segs = rel.split("/");
243
+ let pruned = false;
244
+ for (const s of segs) {
245
+ if (SKIP.has(s)) {
246
+ pruned = true;
247
+ break;
248
+ }
249
+ }
250
+ if (pruned)
251
+ continue;
252
+ if (this.regex.test(rel)) {
253
+ yield absolute ? resolve(cwd, rel) : rel;
168
254
  }
169
255
  }
170
256
  }
@@ -195,15 +281,31 @@ class CryptoHasherPolyfill {
195
281
  }
196
282
  function ensureBunPolyfill() {
197
283
  const g = globalThis;
198
- if (typeof g.Bun !== "undefined")
284
+ if (typeof g.Bun === "undefined") {
285
+ g.Bun = {
286
+ file: filePolyfill,
287
+ spawn: spawnPolyfill,
288
+ JSONL: { parse: jsonlParsePolyfill },
289
+ Glob: GlobPolyfill,
290
+ CryptoHasher: CryptoHasherPolyfill
291
+ };
199
292
  return;
200
- g.Bun = {
201
- file: filePolyfill,
202
- spawn: spawnPolyfill,
203
- JSONL: { parse: jsonlParsePolyfill },
204
- Glob: GlobPolyfill,
205
- CryptoHasher: CryptoHasherPolyfill
206
- };
293
+ }
294
+ if (typeof g.Bun.Glob !== "function") {
295
+ g.Bun.Glob = GlobPolyfill;
296
+ }
297
+ if (typeof g.Bun.file !== "function") {
298
+ g.Bun.file = filePolyfill;
299
+ }
300
+ if (typeof g.Bun.spawn !== "function") {
301
+ g.Bun.spawn = spawnPolyfill;
302
+ }
303
+ if (!g.Bun.JSONL || typeof g.Bun.JSONL.parse !== "function") {
304
+ g.Bun.JSONL = { parse: jsonlParsePolyfill };
305
+ }
306
+ if (typeof g.Bun.CryptoHasher !== "function") {
307
+ g.Bun.CryptoHasher = CryptoHasherPolyfill;
308
+ }
207
309
  }
208
310
  var init_bun_polyfill = __esm(() => {
209
311
  ensureBunPolyfill();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zephex",
3
- "version": "2.0.16",
3
+ "version": "2.1.0",
4
4
  "description": "Zephex MCP — codebase intelligence tools for AI coding agents. stdio server that runs locally, reads your project files, and proxies AI calls to the Zephex backend.",
5
5
  "type": "module",
6
6
  "main": "dist/cli.js",
@@ -52,6 +52,7 @@
52
52
  "node": ">=24.0.0"
53
53
  },
54
54
  "dependencies": {
55
+ "@clack/prompts": "^0.9.1",
55
56
  "@modelcontextprotocol/sdk": "^1.28.0",
56
57
  "@sentry/node": "^10.46.0",
57
58
  "@supabase/supabase-js": "^2.100.1",
@@ -71,6 +72,7 @@
71
72
  "jose": "^5.10.0",
72
73
  "launchdarkly-node-server-sdk": "^7.0.4",
73
74
  "lru-cache": "^11.2.7",
75
+ "open": "^10.1.0",
74
76
  "puppeteer-core": "^24.40.0",
75
77
  "resend": "^6.9.4",
76
78
  "sanitize-html": "^2.17.2",