codeep 1.3.42 → 2.0.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.
Files changed (59) hide show
  1. package/README.md +208 -0
  2. package/dist/acp/commands.js +770 -7
  3. package/dist/acp/protocol.d.ts +11 -2
  4. package/dist/acp/server.js +179 -11
  5. package/dist/acp/session.d.ts +3 -0
  6. package/dist/acp/session.js +5 -0
  7. package/dist/api/index.js +39 -6
  8. package/dist/config/index.d.ts +13 -0
  9. package/dist/config/index.js +45 -0
  10. package/dist/config/providers.js +76 -1
  11. package/dist/renderer/App.d.ts +12 -0
  12. package/dist/renderer/App.js +96 -4
  13. package/dist/renderer/agentExecution.js +5 -0
  14. package/dist/renderer/commands.js +348 -2
  15. package/dist/renderer/components/Login.d.ts +1 -0
  16. package/dist/renderer/components/Login.js +24 -9
  17. package/dist/renderer/handlers.d.ts +11 -1
  18. package/dist/renderer/handlers.js +30 -0
  19. package/dist/renderer/main.js +73 -0
  20. package/dist/utils/agent.d.ts +17 -0
  21. package/dist/utils/agent.js +91 -7
  22. package/dist/utils/agentChat.d.ts +10 -2
  23. package/dist/utils/agentChat.js +48 -9
  24. package/dist/utils/agentStream.js +6 -2
  25. package/dist/utils/checkpoints.d.ts +93 -0
  26. package/dist/utils/checkpoints.js +205 -0
  27. package/dist/utils/context.d.ts +24 -0
  28. package/dist/utils/context.js +57 -0
  29. package/dist/utils/customCommands.d.ts +62 -0
  30. package/dist/utils/customCommands.js +201 -0
  31. package/dist/utils/hooks.d.ts +97 -0
  32. package/dist/utils/hooks.js +223 -0
  33. package/dist/utils/mcpClient.d.ts +229 -0
  34. package/dist/utils/mcpClient.js +497 -0
  35. package/dist/utils/mcpConfig.d.ts +55 -0
  36. package/dist/utils/mcpConfig.js +177 -0
  37. package/dist/utils/mcpMarketplace.d.ts +49 -0
  38. package/dist/utils/mcpMarketplace.js +175 -0
  39. package/dist/utils/mcpRegistry.d.ts +129 -0
  40. package/dist/utils/mcpRegistry.js +427 -0
  41. package/dist/utils/mcpSamplingBridge.d.ts +32 -0
  42. package/dist/utils/mcpSamplingBridge.js +88 -0
  43. package/dist/utils/mcpStreamableHttp.d.ts +65 -0
  44. package/dist/utils/mcpStreamableHttp.js +207 -0
  45. package/dist/utils/openrouterPrefs.d.ts +36 -0
  46. package/dist/utils/openrouterPrefs.js +83 -0
  47. package/dist/utils/skillBundles.d.ts +84 -0
  48. package/dist/utils/skillBundles.js +257 -0
  49. package/dist/utils/skillBundlesCloud.d.ts +66 -0
  50. package/dist/utils/skillBundlesCloud.js +196 -0
  51. package/dist/utils/tokenTracker.d.ts +14 -2
  52. package/dist/utils/tokenTracker.js +59 -41
  53. package/dist/utils/toolExecution.d.ts +17 -1
  54. package/dist/utils/toolExecution.js +184 -6
  55. package/dist/utils/tools.d.ts +22 -6
  56. package/dist/utils/tools.js +83 -8
  57. package/package.json +3 -2
  58. package/bin/codeep-macos-arm64 +0 -0
  59. package/bin/codeep-macos-x64 +0 -0
@@ -14,6 +14,8 @@ import { loadIgnoreRules, isIgnored } from './gitignore.js';
14
14
  import { normalizeToolName } from './toolParsing.js';
15
15
  import { getZaiMcpConfig, getZaiVisionConfig, getMinimaxMcpConfig, callZaiMcp, callZaiVisionApi, callMinimaxApi } from './mcpIntegration.js';
16
16
  import { logger } from './logger.js';
17
+ import { runHook } from './hooks.js';
18
+ import { isMcpToolName, callSessionTool, isVirtualMcpToolName, callSessionVirtualTool } from './mcpRegistry.js';
17
19
  const debug = (...args) => {
18
20
  if (process.env.CODEEP_DEBUG === '1') {
19
21
  logger.debug(args.map(String).join(' '));
@@ -146,11 +148,114 @@ function htmlToText(html) {
146
148
  }
147
149
  /**
148
150
  * Execute a tool call and return the result.
151
+ *
152
+ * `fs` is optional — if provided and the relevant method is defined, file
153
+ * read/write is delegated to the client. Otherwise we fall back to direct
154
+ * disk I/O. A delegated call that throws also falls back to disk so a
155
+ * single client hiccup doesn't kill the agent loop.
149
156
  */
150
- export async function executeTool(toolCall, projectRoot) {
157
+ export async function executeTool(toolCall, projectRoot, fs, mcpSessionId) {
151
158
  const tool = normalizeToolName(toolCall.tool);
152
159
  const parameters = toolCall.parameters;
153
160
  debug(`Executing tool: ${tool}`, parameters.path || parameters.command || '');
161
+ // pre_tool_call hook runs first, even for MCP tools. A `pre_tool_call`
162
+ // script is the policy gate (block writes to certain dirs, refuse risky
163
+ // commands, deny outbound calls to specific MCP servers, etc.), so
164
+ // letting MCP traffic bypass it would defeat the gate's purpose.
165
+ // Failing closed is the safe default.
166
+ const preHook = runHook({ event: 'pre_tool_call', workspaceRoot: projectRoot, toolName: tool, toolParams: parameters });
167
+ if (preHook.blocked) {
168
+ const msg = preHook.stderr?.trim() || preHook.stdout?.trim() || `pre_tool_call hook exited ${preHook.exitCode}`;
169
+ return {
170
+ success: false,
171
+ output: '',
172
+ error: `Blocked by pre_tool_call hook: ${msg}`,
173
+ tool,
174
+ parameters,
175
+ };
176
+ }
177
+ // MCP-prefixed tool names (`<server>__<tool>`) route through the
178
+ // per-session MCP registry. We still fire on_error so logging hooks
179
+ // see MCP failures the same way they see built-in failures, but skip
180
+ // post_edit — MCP tools aren't file-edit operations in the local sense
181
+ // (they may do anything; we don't have enough info to call it an edit).
182
+ //
183
+ // IMPORTANT: lookup uses the RAW tool name from the model, not the
184
+ // normalized one. `normalizeToolName` lowercases and converts hyphens
185
+ // to underscores — fine for built-in tools, but it mangles MCP server
186
+ // names that legitimately contain hyphens (e.g. `my-fs__read_file`
187
+ // would become `my_fs__read_file` and miss the registry lookup).
188
+ const rawTool = toolCall.tool;
189
+ // invoke_skill — agent-driven skill bundle invocation. Returns the
190
+ // bundle's SKILL.md body so the agent can read its instructions in
191
+ // the next iteration. Project-scoped bundles win over global.
192
+ if (rawTool === 'invoke_skill') {
193
+ const name = String(parameters.name ?? '').trim();
194
+ if (!name) {
195
+ return { success: false, output: '', error: 'invoke_skill requires a `name` argument', tool: rawTool, parameters };
196
+ }
197
+ try {
198
+ const { findSkillBundle } = await import('./skillBundles.js');
199
+ const bundle = findSkillBundle(name, projectRoot);
200
+ if (!bundle) {
201
+ return { success: false, output: '', error: `Skill "${name}" not found. Use the catalog in your system prompt or ask the user to /skills bundles.`, tool: rawTool, parameters };
202
+ }
203
+ // Prefix the body with a header so the model sees clear framing.
204
+ const output = `# Skill: ${bundle.name}\n_${bundle.description}_\n\n${bundle.body}`;
205
+ return { success: true, output, tool: rawTool, parameters };
206
+ }
207
+ catch (err) {
208
+ return { success: false, output: '', error: err.message, tool: rawTool, parameters };
209
+ }
210
+ }
211
+ if (isMcpToolName(rawTool) && mcpSessionId) {
212
+ let result;
213
+ try {
214
+ // Virtual wrappers (resource_list / resource_read / prompt_list /
215
+ // prompt_get) live in mcpRegistry alongside the real tools. We
216
+ // dispatch them through their own helper so the registry stays the
217
+ // single source of truth for what's namespaced under each server.
218
+ const output = isVirtualMcpToolName(rawTool)
219
+ ? await callSessionVirtualTool(mcpSessionId, rawTool, parameters)
220
+ : await callSessionTool(mcpSessionId, rawTool, parameters);
221
+ result = { success: true, output, tool: rawTool, parameters };
222
+ }
223
+ catch (err) {
224
+ result = { success: false, output: '', error: err.message, tool: rawTool, parameters };
225
+ }
226
+ if (!result.success) {
227
+ runHook({ event: 'on_error', workspaceRoot: projectRoot, toolName: rawTool, toolParams: parameters });
228
+ }
229
+ return result;
230
+ }
231
+ // Wrap the original dispatch so we can run on_error / post_edit hooks
232
+ // around it without indenting every case.
233
+ const result = await dispatchTool(tool, parameters, projectRoot, fs, toolCall);
234
+ if (!result.success) {
235
+ runHook({
236
+ event: 'on_error',
237
+ workspaceRoot: projectRoot,
238
+ toolName: tool,
239
+ toolParams: parameters,
240
+ });
241
+ }
242
+ else if (tool === 'write_file' || tool === 'edit_file') {
243
+ const filePath = parameters.path;
244
+ if (filePath) {
245
+ const abs = isAbsolute(filePath) ? filePath : join(projectRoot, filePath);
246
+ // post_edit is advisory — non-zero exit doesn't roll back the write.
247
+ // Typical use is `prettier --write "$CODEEP_HOOK_FILE"`.
248
+ runHook({
249
+ event: 'post_edit',
250
+ workspaceRoot: projectRoot,
251
+ toolName: tool,
252
+ filePath: abs,
253
+ });
254
+ }
255
+ }
256
+ return result;
257
+ }
258
+ async function dispatchTool(tool, parameters, projectRoot, fs, toolCall) {
154
259
  try {
155
260
  switch (tool) {
156
261
  case 'read_file': {
@@ -160,6 +265,28 @@ export async function executeTool(toolCall, projectRoot) {
160
265
  const validation = validatePath(path, projectRoot);
161
266
  if (!validation.valid)
162
267
  return { success: false, output: '', error: validation.error, tool, parameters };
268
+ // Try client delegation first. The client owns the source of truth
269
+ // for unsaved buffers, so we prefer it even if the file also exists
270
+ // on disk. The 100 KB cap below is enforced on the delegated result
271
+ // too — a malicious or misconfigured client could otherwise return
272
+ // an arbitrarily large blob that blows up the agent's context.
273
+ if (fs?.readTextFile) {
274
+ try {
275
+ const content = await fs.readTextFile(validation.absolutePath);
276
+ // Cap is on character count, not raw bytes — JS strings are
277
+ // UTF-16 in memory, so 100K chars ≈ 200K bytes of process
278
+ // memory plus whatever the model context costs. Either way,
279
+ // a 1GB blob from a misbehaving client gets rejected here.
280
+ if (content.length > 100 * 1024) {
281
+ return { success: false, output: '', error: `File too large (${content.length} chars via client). Max: 100K chars`, tool, parameters };
282
+ }
283
+ return { success: true, output: content, tool, parameters };
284
+ }
285
+ catch (err) {
286
+ debug('fs/read_text_file delegation failed, falling back to disk:', err);
287
+ // fall through to disk read
288
+ }
289
+ }
163
290
  if (!existsSync(validation.absolutePath))
164
291
  return { success: false, output: '', error: `File not found: ${path}`, tool, parameters };
165
292
  const stat = statSync(validation.absolutePath);
@@ -183,12 +310,30 @@ export async function executeTool(toolCall, projectRoot) {
183
310
  const validation = validatePath(path, projectRoot);
184
311
  if (!validation.valid)
185
312
  return { success: false, output: '', error: validation.error, tool, parameters };
313
+ // Client delegation: lets editors keep dirty buffers, undo history,
314
+ // and lint-on-save reactions consistent. The client is responsible
315
+ // for creating parent directories — VS Code's WorkspaceEdit does;
316
+ // for the disk fallback below we do it ourselves.
317
+ if (fs?.writeTextFile) {
318
+ try {
319
+ const existed = existsSync(validation.absolutePath);
320
+ await fs.writeTextFile(validation.absolutePath, content);
321
+ // Only record after the write actually succeeded — otherwise a
322
+ // failed delegation that falls through to disk would double-log.
323
+ recordWrite(validation.absolutePath);
324
+ return { success: true, output: `${existed ? 'Updated' : 'Created'} file: ${path}`, tool, parameters };
325
+ }
326
+ catch (err) {
327
+ debug('fs/write_text_file delegation failed, falling back to disk:', err);
328
+ // fall through to disk write
329
+ }
330
+ }
186
331
  const dir = dirname(validation.absolutePath);
187
332
  if (!existsSync(dir))
188
333
  mkdirSync(dir, { recursive: true });
189
- recordWrite(validation.absolutePath);
190
334
  const existed = existsSync(validation.absolutePath);
191
335
  writeFileSync(validation.absolutePath, content, 'utf-8');
336
+ recordWrite(validation.absolutePath);
192
337
  return { success: true, output: `${existed ? 'Updated' : 'Created'} file: ${path}`, tool, parameters };
193
338
  }
194
339
  case 'edit_file': {
@@ -201,9 +346,27 @@ export async function executeTool(toolCall, projectRoot) {
201
346
  const validation = validatePath(path, projectRoot);
202
347
  if (!validation.valid)
203
348
  return { success: false, output: '', error: validation.error, tool, parameters };
204
- if (!existsSync(validation.absolutePath))
205
- return { success: false, output: '', error: `File not found: ${path}`, tool, parameters };
206
- const content = readFileSync(validation.absolutePath, 'utf-8');
349
+ // Read through the client when delegation is available — the dirty
350
+ // buffer in the editor is the authoritative version for an edit.
351
+ let content;
352
+ let readDelegated = false;
353
+ if (fs?.readTextFile) {
354
+ try {
355
+ content = await fs.readTextFile(validation.absolutePath);
356
+ readDelegated = true;
357
+ }
358
+ catch (err) {
359
+ debug('fs/read_text_file (in edit_file) failed, falling back to disk:', err);
360
+ if (!existsSync(validation.absolutePath))
361
+ return { success: false, output: '', error: `File not found: ${path}`, tool, parameters };
362
+ content = readFileSync(validation.absolutePath, 'utf-8');
363
+ }
364
+ }
365
+ else {
366
+ if (!existsSync(validation.absolutePath))
367
+ return { success: false, output: '', error: `File not found: ${path}`, tool, parameters };
368
+ content = readFileSync(validation.absolutePath, 'utf-8');
369
+ }
207
370
  if (!content.includes(oldText)) {
208
371
  return { success: false, output: '', error: 'Text not found in file. Make sure old_text matches exactly.', tool, parameters };
209
372
  }
@@ -217,7 +380,22 @@ export async function executeTool(toolCall, projectRoot) {
217
380
  return { success: false, output: '', error: `old_text matches ${matchCount} locations in the file. Provide more surrounding context to make it unique (only 1 match allowed).`, tool, parameters };
218
381
  }
219
382
  recordEdit(validation.absolutePath);
220
- writeFileSync(validation.absolutePath, content.replace(oldText, newText), 'utf-8');
383
+ const updated = content.replace(oldText, newText);
384
+ if (fs?.writeTextFile) {
385
+ try {
386
+ await fs.writeTextFile(validation.absolutePath, updated);
387
+ return { success: true, output: `Edited file: ${path}`, tool, parameters };
388
+ }
389
+ catch (err) {
390
+ debug('fs/write_text_file (in edit_file) failed, falling back to disk:', err);
391
+ // If we read through the client but write back to disk, the
392
+ // editor's dirty buffer could be discarded next save. Log and
393
+ // continue — better than silently dropping the edit.
394
+ if (readDelegated)
395
+ debug('warning: edit_file read via client but writing to disk');
396
+ }
397
+ }
398
+ writeFileSync(validation.absolutePath, updated, 'utf-8');
221
399
  return { success: true, output: `Edited file: ${path}`, tool, parameters };
222
400
  }
223
401
  case 'delete_file': {
@@ -312,16 +312,32 @@ export declare const AGENT_TOOLS: {
312
312
  };
313
313
  };
314
314
  /**
315
- * Format tool definitions for system prompt (text-based fallback)
315
+ * Shape of additional (non-built-in) tools merged into the agent's catalog.
316
+ * Used by MCP integration — the registered tool's prefixed name and the raw
317
+ * MCP `tools/list` schema are both passed through.
316
318
  */
317
- export declare function formatToolDefinitions(): string;
319
+ export interface AdditionalToolDef {
320
+ /** Name the agent must use to invoke this tool (e.g. `fs__read_file`). */
321
+ name: string;
322
+ description?: string;
323
+ /** JSON-schema-like `input_schema` from the MCP server's tools/list reply. */
324
+ inputSchema?: Record<string, unknown>;
325
+ }
326
+ /**
327
+ * Format tool definitions for system prompt (text-based fallback).
328
+ * Optionally appends an "Additional tools" section listing tools from
329
+ * sources outside the built-in catalog (currently MCP servers).
330
+ */
331
+ export declare function formatToolDefinitions(additionalTools?: AdditionalToolDef[]): string;
318
332
  /**
319
- * Get tools in OpenAI Function Calling format
333
+ * Get tools in OpenAI Function Calling format.
334
+ * Additional tools (e.g. MCP) are appended with their JSON-schema as-is.
320
335
  */
321
- export declare function getOpenAITools(): OpenAITool[];
336
+ export declare function getOpenAITools(additionalTools?: AdditionalToolDef[]): OpenAITool[];
322
337
  /**
323
- * Get tools in Anthropic Tool Use format
338
+ * Get tools in Anthropic Tool Use format.
339
+ * Additional tools (e.g. MCP) are appended with their JSON-schema as-is.
324
340
  */
325
- export declare function getAnthropicTools(): AnthropicTool[];
341
+ export declare function getAnthropicTools(additionalTools?: AdditionalToolDef[]): AnthropicTool[];
326
342
  export { normalizeToolName, parseOpenAIToolCalls, parseAnthropicToolCalls, parseToolCalls } from './toolParsing';
327
343
  export { executeTool, validatePath, createActionLog } from './toolExecution';
@@ -155,9 +155,11 @@ function getFilteredToolEntries() {
155
155
  });
156
156
  }
157
157
  /**
158
- * Format tool definitions for system prompt (text-based fallback)
158
+ * Format tool definitions for system prompt (text-based fallback).
159
+ * Optionally appends an "Additional tools" section listing tools from
160
+ * sources outside the built-in catalog (currently MCP servers).
159
161
  */
160
- export function formatToolDefinitions() {
162
+ export function formatToolDefinitions(additionalTools) {
161
163
  const lines = [];
162
164
  for (const [name, tool] of getFilteredToolEntries()) {
163
165
  lines.push(`### ${name}`);
@@ -169,13 +171,64 @@ export function formatToolDefinitions() {
169
171
  }
170
172
  lines.push('');
171
173
  }
174
+ if (additionalTools?.length) {
175
+ // Token budget caps. MCP servers can return tools with absurdly verbose
176
+ // JSON Schema definitions (multi-KB per tool). Without caps a 30-tool
177
+ // server eats ~10K tokens of every prompt. Per-tool 2KB + total 16KB
178
+ // is enough for the model to learn parameter shapes without breaking
179
+ // the bank.
180
+ const PER_TOOL_CAP = 2048;
181
+ const TOTAL_CAP = 16_384;
182
+ let budget = TOTAL_CAP;
183
+ let skipped = 0;
184
+ lines.push('## Additional tools (from MCP servers)');
185
+ lines.push('');
186
+ for (const tool of additionalTools) {
187
+ if (budget <= 0) {
188
+ skipped++;
189
+ continue;
190
+ }
191
+ const headerLines = [`### ${tool.name}`];
192
+ if (tool.description)
193
+ headerLines.push(tool.description);
194
+ let schemaBlock = '';
195
+ if (tool.inputSchema) {
196
+ let schemaJson = JSON.stringify(tool.inputSchema, null, 2);
197
+ if (schemaJson.length > PER_TOOL_CAP) {
198
+ schemaJson = schemaJson.slice(0, PER_TOOL_CAP) + `\n… (truncated, ${schemaJson.length - PER_TOOL_CAP} more chars)`;
199
+ }
200
+ schemaBlock = `Parameters (JSON Schema):\n\`\`\`json\n${schemaJson}\n\`\`\``;
201
+ }
202
+ const entry = [...headerLines, schemaBlock, ''].filter(Boolean).join('\n');
203
+ if (entry.length > budget) {
204
+ skipped++;
205
+ continue;
206
+ }
207
+ lines.push(entry);
208
+ budget -= entry.length;
209
+ }
210
+ if (skipped > 0) {
211
+ lines.push(`_(${skipped} more MCP tool${skipped === 1 ? '' : 's'} omitted — total catalog exceeded ${TOTAL_CAP}-char budget.)_`);
212
+ }
213
+ }
172
214
  return lines.join('\n');
173
215
  }
216
+ /** Build a generic JSON-schema parameters object from an additional-tool spec.
217
+ * Falls back to a permissive `additionalProperties: true` schema if the MCP
218
+ * server didn't supply one — that lets the model still attempt the call. */
219
+ function additionalToolSchema(tool) {
220
+ if (tool.inputSchema && typeof tool.inputSchema === 'object') {
221
+ // Most MCP servers already return a JSON-schema-shaped object.
222
+ return tool.inputSchema;
223
+ }
224
+ return { type: 'object', properties: {}, additionalProperties: true };
225
+ }
174
226
  /**
175
- * Get tools in OpenAI Function Calling format
227
+ * Get tools in OpenAI Function Calling format.
228
+ * Additional tools (e.g. MCP) are appended with their JSON-schema as-is.
176
229
  */
177
- export function getOpenAITools() {
178
- return getFilteredToolEntries().map(([name, tool]) => {
230
+ export function getOpenAITools(additionalTools) {
231
+ const builtin = getFilteredToolEntries().map(([name, tool]) => {
179
232
  const properties = {};
180
233
  const required = [];
181
234
  for (const [param, info] of Object.entries(tool.parameters)) {
@@ -198,12 +251,26 @@ export function getOpenAITools() {
198
251
  },
199
252
  };
200
253
  });
254
+ if (!additionalTools?.length)
255
+ return builtin;
256
+ const extra = additionalTools.map(t => ({
257
+ type: 'function',
258
+ function: {
259
+ name: t.name,
260
+ description: t.description ?? `External tool: ${t.name}`,
261
+ // Cast — OpenAITool.function.parameters is statically typed for
262
+ // built-ins, but MCP schemas vary. The runtime API doesn't care.
263
+ parameters: additionalToolSchema(t),
264
+ },
265
+ }));
266
+ return [...builtin, ...extra];
201
267
  }
202
268
  /**
203
- * Get tools in Anthropic Tool Use format
269
+ * Get tools in Anthropic Tool Use format.
270
+ * Additional tools (e.g. MCP) are appended with their JSON-schema as-is.
204
271
  */
205
- export function getAnthropicTools() {
206
- return getFilteredToolEntries().map(([name, tool]) => {
272
+ export function getAnthropicTools(additionalTools) {
273
+ const builtin = getFilteredToolEntries().map(([name, tool]) => {
207
274
  const properties = {};
208
275
  const required = [];
209
276
  for (const [param, info] of Object.entries(tool.parameters)) {
@@ -223,6 +290,14 @@ export function getAnthropicTools() {
223
290
  input_schema: { type: 'object', properties, required },
224
291
  };
225
292
  });
293
+ if (!additionalTools?.length)
294
+ return builtin;
295
+ const extra = additionalTools.map(t => ({
296
+ name: t.name,
297
+ description: t.description ?? `External tool: ${t.name}`,
298
+ input_schema: additionalToolSchema(t),
299
+ }));
300
+ return [...builtin, ...extra];
226
301
  }
227
302
  // Re-export from sub-modules so existing imports don't break
228
303
  export { normalizeToolName, parseOpenAIToolCalls, parseAnthropicToolCalls, parseToolCalls } from './toolParsing.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeep",
3
- "version": "1.3.42",
3
+ "version": "2.0.0",
4
4
  "description": "AI-powered coding assistant built for the terminal. Multiple LLM providers, project-aware context, and a seamless development workflow.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -57,10 +57,11 @@
57
57
  "node": ">=20.0.0"
58
58
  },
59
59
  "files": [
60
- "bin/**/*",
60
+ "bin/codeep.js",
61
61
  "dist/**/*",
62
62
  "!dist/**/*.test.js",
63
63
  "!dist/**/*.test.d.ts",
64
+ "!dist/zed/**",
64
65
  "README.md",
65
66
  "LICENSE"
66
67
  ],
Binary file
Binary file