@gemdoq/codi 0.1.2 → 0.1.3

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.
package/dist/cli.js CHANGED
@@ -330,10 +330,12 @@ import chalk13 from "chalk";
330
330
  // src/setup-wizard.ts
331
331
  init_esm_shims();
332
332
  import * as fs from "fs";
333
+ import * as os from "os";
333
334
  import * as path2 from "path";
334
335
  import chalk from "chalk";
335
336
  import * as readline from "readline/promises";
336
337
  import { stdin as input, stdout as output } from "process";
338
+ var isWindows = os.platform() === "win32";
337
339
  var SETTINGS_DIR = path2.join(
338
340
  process.env["HOME"] || process.env["USERPROFILE"] || "~",
339
341
  ".codi"
@@ -425,7 +427,8 @@ async function runSetupWizard() {
425
427
  rl.close();
426
428
  if (!apiKey.trim()) {
427
429
  console.log(chalk.yellow("\n No API key provided. Setup cancelled."));
428
- console.log(chalk.dim(` You can set it later: export ${envVarName}=your-key
430
+ const laterCmd = isWindows ? `$env:${envVarName}="your-key"` : `export ${envVarName}=your-key`;
431
+ console.log(chalk.dim(` You can set it later: ${laterCmd}
429
432
  `));
430
433
  return null;
431
434
  }
@@ -441,11 +444,20 @@ async function runSetupWizard() {
441
444
  const trimmedKey = apiKey.trim();
442
445
  if (saveChoice.trim() === "2") {
443
446
  console.log("");
444
- console.log(chalk.bold(" Add this to your shell profile (~/.zshrc or ~/.bashrc):"));
445
- console.log("");
446
- console.log(chalk.cyan(` export ${envVarName}=${trimmedKey}`));
447
- console.log("");
448
- console.log(chalk.dim(" Then restart your terminal or run: source ~/.zshrc"));
447
+ if (isWindows) {
448
+ console.log(chalk.bold(" Run this command in PowerShell (admin) to set permanently:"));
449
+ console.log("");
450
+ console.log(chalk.cyan(` [System.Environment]::SetEnvironmentVariable('${envVarName}', '${trimmedKey}', 'User')`));
451
+ console.log("");
452
+ console.log(chalk.dim(" Or set temporarily for this session:"));
453
+ console.log(chalk.cyan(` $env:${envVarName}="${trimmedKey}"`));
454
+ } else {
455
+ console.log(chalk.bold(" Add this to your shell profile (~/.zshrc or ~/.bashrc):"));
456
+ console.log("");
457
+ console.log(chalk.cyan(` export ${envVarName}=${trimmedKey}`));
458
+ console.log("");
459
+ console.log(chalk.dim(" Then restart your terminal or run: source ~/.zshrc"));
460
+ }
449
461
  console.log("");
450
462
  return { apiKey: trimmedKey, provider };
451
463
  }
@@ -481,7 +493,8 @@ async function runSetupWizard() {
481
493
  } catch (err) {
482
494
  console.log(chalk.red(`
483
495
  Failed to save settings: ${err}`));
484
- console.log(chalk.dim(` Set manually: export ${envVarName}=${trimmedKey}
496
+ const manualCmd = isWindows ? `$env:${envVarName}="${trimmedKey}"` : `export ${envVarName}=${trimmedKey}`;
497
+ console.log(chalk.dim(` Set manually: ${manualCmd}
485
498
  `));
486
499
  }
487
500
  return { apiKey: trimmedKey, provider };
@@ -622,6 +635,7 @@ var configManager = new ConfigManager();
622
635
  init_esm_shims();
623
636
  import * as readline2 from "readline/promises";
624
637
  import { stdin as input2, stdout as output2 } from "process";
638
+ import * as os2 from "os";
625
639
  import chalk4 from "chalk";
626
640
  import { execSync } from "child_process";
627
641
  import { edit } from "external-editor";
@@ -886,10 +900,12 @@ var Repl = class {
886
900
  const cmd = input3.slice(1).trim();
887
901
  if (!cmd) return;
888
902
  try {
903
+ const shell = os2.platform() === "win32" ? "powershell.exe" : void 0;
889
904
  const result = execSync(cmd, {
890
905
  encoding: "utf-8",
891
906
  stdio: ["inherit", "pipe", "pipe"],
892
- timeout: 3e4
907
+ timeout: 3e4,
908
+ shell
893
909
  });
894
910
  console.log(result);
895
911
  } catch (err) {
@@ -905,8 +921,8 @@ var Repl = class {
905
921
  for (const match of atMatches) {
906
922
  const filePath = match.slice(1);
907
923
  try {
908
- const { readFileSync: readFileSync12 } = await import("fs");
909
- const content = readFileSync12(filePath, "utf-8");
924
+ const { readFileSync: readFileSync13 } = await import("fs");
925
+ const content = readFileSync13(filePath, "utf-8");
910
926
  message = message.replace(match, `
911
927
  [File: ${filePath}]
912
928
  \`\`\`
@@ -1438,7 +1454,7 @@ function sleep(ms) {
1438
1454
 
1439
1455
  // src/agent/system-prompt.ts
1440
1456
  init_esm_shims();
1441
- import * as os from "os";
1457
+ import * as os3 from "os";
1442
1458
  import { execSync as execSync2 } from "child_process";
1443
1459
  var ROLE_DEFINITION = `You are Codi (\uCF54\uB514), a terminal-based AI coding agent. You help users with software engineering tasks including writing code, debugging, refactoring, and explaining code. You have access to tools for file manipulation, code search, shell execution, and more.`;
1444
1460
  var TOOL_HIERARCHY = `# Tool Usage Rules
@@ -1450,6 +1466,21 @@ var TOOL_HIERARCHY = `# Tool Usage Rules
1450
1466
  - Reserve bash for system commands that have no dedicated tool
1451
1467
  - Use sub_agent for complex multi-step exploration tasks
1452
1468
  - Call multiple tools in parallel when they are independent`;
1469
+ var WINDOWS_RULES = `# Windows Shell Rules
1470
+ You are running on Windows. The shell is PowerShell. Follow these rules:
1471
+ - Use PowerShell syntax, NOT bash/sh syntax
1472
+ - Path separators: use \\\\ or / (PowerShell accepts both)
1473
+ - mkdir works without -p flag (PowerShell creates parent directories automatically)
1474
+ - Use gradlew.bat instead of ./gradlew for Gradle projects
1475
+ - Use mvnw.cmd instead of ./mvnw for Maven projects
1476
+ - Do NOT use chmod (not available on Windows)
1477
+ - Do NOT use HEREDOC (cat <<EOF) \u2014 use write_file tool instead
1478
+ - Use Remove-Item instead of rm -rf
1479
+ - Use Get-ChildItem instead of ls -la
1480
+ - Use Invoke-WebRequest or curl.exe instead of curl
1481
+ - Environment variables: use $env:VAR_NAME instead of $VAR_NAME
1482
+ - Use semicolons (;) or separate commands instead of && for chaining
1483
+ - Scripts: use .ps1 files instead of .sh files`;
1453
1484
  var CODE_RULES = `# Code Modification Rules
1454
1485
  - ALWAYS read a file before editing it
1455
1486
  - Prefer edit_file over write_file for existing files
@@ -1485,6 +1516,9 @@ function buildSystemPrompt(context) {
1485
1516
  fragments.push(ROLE_DEFINITION);
1486
1517
  fragments.push(buildEnvironmentInfo(context));
1487
1518
  fragments.push(TOOL_HIERARCHY);
1519
+ if (os3.platform() === "win32") {
1520
+ fragments.push(WINDOWS_RULES);
1521
+ }
1488
1522
  fragments.push(CODE_RULES);
1489
1523
  fragments.push(GIT_SAFETY);
1490
1524
  fragments.push(RESPONSE_STYLE);
@@ -1513,8 +1547,8 @@ function buildEnvironmentInfo(context) {
1513
1547
  const lines = [
1514
1548
  "# Environment",
1515
1549
  `- Date: ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}`,
1516
- `- OS: ${os.platform()} ${os.release()}`,
1517
- `- Shell: ${process.env["SHELL"] || "unknown"}`,
1550
+ `- OS: ${os3.platform()} ${os3.release()}`,
1551
+ `- Shell: ${process.env["SHELL"] || process.env["COMSPEC"] || "unknown"}`,
1518
1552
  `- Working Directory: ${context.cwd}`,
1519
1553
  `- Model: ${context.model}`,
1520
1554
  `- Provider: ${context.provider}`
@@ -2075,6 +2109,13 @@ async function promptUser(tool, input3) {
2075
2109
  // src/hooks/hook-manager.ts
2076
2110
  init_esm_shims();
2077
2111
  import { exec } from "child_process";
2112
+ import * as os4 from "os";
2113
+ function getDefaultShell() {
2114
+ if (os4.platform() === "win32") {
2115
+ return "powershell.exe";
2116
+ }
2117
+ return void 0;
2118
+ }
2078
2119
  var HookManager = class {
2079
2120
  async runHooks(event, context) {
2080
2121
  const config = configManager.get();
@@ -2110,7 +2151,8 @@ var HookManager = class {
2110
2151
  const proc = exec(command, {
2111
2152
  timeout: timeout || 5e3,
2112
2153
  cwd: process.cwd(),
2113
- env: { ...process.env }
2154
+ env: { ...process.env },
2155
+ shell: getDefaultShell()
2114
2156
  }, (err, stdout, stderr) => {
2115
2157
  if (err) {
2116
2158
  if (err.code === 2) {
@@ -2371,6 +2413,7 @@ var subAgentTool = {
2371
2413
  // src/config/slash-commands.ts
2372
2414
  init_esm_shims();
2373
2415
  import * as fs8 from "fs";
2416
+ import * as os5 from "os";
2374
2417
  import * as path9 from "path";
2375
2418
  import chalk11 from "chalk";
2376
2419
  function createBuiltinCommands() {
@@ -2719,6 +2762,146 @@ ${content}
2719
2762
  return true;
2720
2763
  }
2721
2764
  },
2765
+ {
2766
+ name: "/commit",
2767
+ description: "Generate commit message and commit with AI",
2768
+ handler: async (_args, ctx) => {
2769
+ const { execSync: execSync5 } = await import("child_process");
2770
+ try {
2771
+ const staged = execSync5("git diff --cached", { encoding: "utf-8", cwd: process.cwd() });
2772
+ const unstaged = execSync5("git diff", { encoding: "utf-8", cwd: process.cwd() });
2773
+ const diff = staged + unstaged;
2774
+ if (!diff.trim()) {
2775
+ console.log(chalk11.dim("\nNo changes to commit.\n"));
2776
+ return true;
2777
+ }
2778
+ ctx.conversation.addUserMessage(
2779
+ `\uB2E4\uC74C git diff\uB97C \uBD84\uC11D\uD574\uC11C \uC801\uC808\uD55C \uCEE4\uBC0B \uBA54\uC2DC\uC9C0\uB97C \uC0DD\uC131\uD558\uACE0, git \uB3C4\uAD6C\uB85C \uBCC0\uACBD\uB41C \uD30C\uC77C\uC744 add\uD558\uACE0 \uCEE4\uBC0B\uD574\uC918.
2780
+
2781
+ \`\`\`diff
2782
+ ${diff}
2783
+ \`\`\``
2784
+ );
2785
+ return false;
2786
+ } catch {
2787
+ console.log(chalk11.yellow("Not a git repository or git not available."));
2788
+ return true;
2789
+ }
2790
+ }
2791
+ },
2792
+ {
2793
+ name: "/review",
2794
+ description: "AI code review of current changes",
2795
+ handler: async (_args, ctx) => {
2796
+ const { execSync: execSync5 } = await import("child_process");
2797
+ try {
2798
+ const staged = execSync5("git diff --cached", { encoding: "utf-8", cwd: process.cwd() });
2799
+ const unstaged = execSync5("git diff", { encoding: "utf-8", cwd: process.cwd() });
2800
+ const diff = staged + unstaged;
2801
+ if (!diff.trim()) {
2802
+ console.log(chalk11.dim("\nNo changes to review.\n"));
2803
+ return true;
2804
+ }
2805
+ ctx.conversation.addUserMessage(
2806
+ `\uB2E4\uC74C git diff\uB97C \uCF54\uB4DC \uB9AC\uBDF0\uD574\uC918. \uBCF4\uC548 \uCDE8\uC57D\uC810, \uBC84\uADF8, \uC131\uB2A5, \uCF54\uB4DC \uC2A4\uD0C0\uC77C \uAD00\uC810\uC5D0\uC11C \uBD84\uC11D\uD558\uACE0 \uAC1C\uC120 \uC0AC\uD56D\uC744 \uC54C\uB824\uC918.
2807
+
2808
+ \`\`\`diff
2809
+ ${diff}
2810
+ \`\`\``
2811
+ );
2812
+ return false;
2813
+ } catch {
2814
+ console.log(chalk11.yellow("Not a git repository or git not available."));
2815
+ return true;
2816
+ }
2817
+ }
2818
+ },
2819
+ {
2820
+ name: "/search",
2821
+ description: "Search past conversation sessions",
2822
+ handler: async (args) => {
2823
+ if (!args) {
2824
+ console.log(chalk11.yellow("Usage: /search <keyword>"));
2825
+ return true;
2826
+ }
2827
+ const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
2828
+ const sessionsDir = path9.join(home, ".codi", "sessions");
2829
+ if (!fs8.existsSync(sessionsDir)) {
2830
+ console.log(chalk11.dim("\nNo sessions found.\n"));
2831
+ return true;
2832
+ }
2833
+ const files = fs8.readdirSync(sessionsDir).filter((f) => f.endsWith(".jsonl"));
2834
+ const results = [];
2835
+ const keyword = args.toLowerCase();
2836
+ for (const file of files) {
2837
+ if (results.length >= 10) break;
2838
+ const filePath = path9.join(sessionsDir, file);
2839
+ const lines = fs8.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
2840
+ for (const line of lines) {
2841
+ if (results.length >= 10) break;
2842
+ if (line.toLowerCase().includes(keyword)) {
2843
+ const sessionId = file.replace(".jsonl", "");
2844
+ const stat = fs8.statSync(filePath);
2845
+ const date = stat.mtime.toISOString().split("T")[0];
2846
+ const preview = line.length > 100 ? line.slice(0, 100) + "..." : line;
2847
+ results.push({ sessionId, date, preview });
2848
+ break;
2849
+ }
2850
+ }
2851
+ }
2852
+ if (results.length === 0) {
2853
+ console.log(chalk11.dim(`
2854
+ No results for "${args}".
2855
+ `));
2856
+ } else {
2857
+ console.log(chalk11.bold(`
2858
+ Search results for "${args}":
2859
+ `));
2860
+ for (const r of results) {
2861
+ console.log(` ${chalk11.cyan(r.sessionId)} ${chalk11.dim(r.date)}`);
2862
+ console.log(` ${chalk11.dim(r.preview)}`);
2863
+ }
2864
+ console.log("");
2865
+ }
2866
+ return true;
2867
+ }
2868
+ },
2869
+ {
2870
+ name: "/fix",
2871
+ description: "Run a command and auto-fix errors (e.g., /fix npm run build)",
2872
+ handler: async (args, ctx) => {
2873
+ if (!args) {
2874
+ console.log(chalk11.yellow("Usage: /fix <command>"));
2875
+ return true;
2876
+ }
2877
+ const { execSync: execSync5 } = await import("child_process");
2878
+ try {
2879
+ const shell = os5.platform() === "win32" ? "powershell.exe" : void 0;
2880
+ const output3 = execSync5(args, { encoding: "utf-8", cwd: process.cwd(), stdio: "pipe", shell });
2881
+ console.log(chalk11.green(`
2882
+ \u2713 Command succeeded. No errors to fix.
2883
+ `));
2884
+ if (output3.trim()) console.log(chalk11.dim(output3));
2885
+ return true;
2886
+ } catch (err) {
2887
+ const error = err;
2888
+ const errorOutput = (error.stderr || "") + (error.stdout || "");
2889
+ console.log(chalk11.red(`
2890
+ Command failed: ${args}
2891
+ `));
2892
+ ctx.conversation.addUserMessage(
2893
+ `\uB2E4\uC74C \uBA85\uB839\uC5B4\uB97C \uC2E4\uD589\uD588\uB354\uB2C8 \uC5D0\uB7EC\uAC00 \uBC1C\uC0DD\uD588\uC5B4. \uC5D0\uB7EC\uB97C \uBD84\uC11D\uD558\uACE0 \uCF54\uB4DC\uB97C \uC218\uC815\uD574\uC918.
2894
+
2895
+ Command: ${args}
2896
+
2897
+ \`\`\`
2898
+ ${errorOutput}
2899
+ \`\`\``
2900
+ );
2901
+ return false;
2902
+ }
2903
+ }
2904
+ },
2722
2905
  {
2723
2906
  name: "/mcp",
2724
2907
  description: "Show MCP server status",
@@ -2872,7 +3055,8 @@ var fileReadTool = {
2872
3055
  }
2873
3056
  }
2874
3057
  try {
2875
- const content = fs9.readFileSync(resolved, "utf-8");
3058
+ const raw = fs9.readFileSync(resolved, "utf-8");
3059
+ const content = raw.replace(/\r\n/g, "\n");
2876
3060
  const lines = content.split("\n");
2877
3061
  const totalLines = lines.length;
2878
3062
  const startLine = Math.max(1, offset || 1);
@@ -2967,7 +3151,9 @@ var fileEditTool = {
2967
3151
  return makeToolError(`File not found: ${resolved}`);
2968
3152
  }
2969
3153
  try {
2970
- let content = fs11.readFileSync(resolved, "utf-8");
3154
+ const raw = fs11.readFileSync(resolved, "utf-8");
3155
+ const hasCrlf = raw.includes("\r\n");
3156
+ let content = hasCrlf ? raw.replace(/\r\n/g, "\n") : raw;
2971
3157
  if (oldString === newString) {
2972
3158
  return makeToolError("old_string and new_string are identical. No changes needed.");
2973
3159
  }
@@ -2999,7 +3185,8 @@ Did you mean this line?
2999
3185
  const idx = content.indexOf(oldString);
3000
3186
  content = content.slice(0, idx) + newString + content.slice(idx + oldString.length);
3001
3187
  }
3002
- fs11.writeFileSync(resolved, content, "utf-8");
3188
+ const output3 = hasCrlf ? content.replace(/\n/g, "\r\n") : content;
3189
+ fs11.writeFileSync(resolved, output3, "utf-8");
3003
3190
  const linesChanged = Math.max(
3004
3191
  oldString.split("\n").length,
3005
3192
  newString.split("\n").length
@@ -3054,7 +3241,9 @@ var fileMultiEditTool = {
3054
3241
  return makeToolError("edits must be a non-empty array of {old_string, new_string} objects");
3055
3242
  }
3056
3243
  try {
3057
- let content = fs12.readFileSync(resolved, "utf-8");
3244
+ const raw = fs12.readFileSync(resolved, "utf-8");
3245
+ const hasCrlf = raw.includes("\r\n");
3246
+ let content = hasCrlf ? raw.replace(/\r\n/g, "\n") : raw;
3058
3247
  for (let i = 0; i < edits.length; i++) {
3059
3248
  const edit2 = edits[i];
3060
3249
  if (!content.includes(edit2.old_string)) {
@@ -3076,7 +3265,8 @@ Searching for: ${edit2.old_string.slice(0, 100)}...`
3076
3265
  edit2.new_string.split("\n").length
3077
3266
  );
3078
3267
  }
3079
- fs12.writeFileSync(resolved, content, "utf-8");
3268
+ const output3 = hasCrlf ? content.replace(/\n/g, "\r\n") : content;
3269
+ fs12.writeFileSync(resolved, output3, "utf-8");
3080
3270
  return makeToolResult(`Applied ${edits.length} edits to ${resolved}`, {
3081
3271
  filePath: resolved,
3082
3272
  linesChanged: totalLinesChanged
@@ -3145,10 +3335,11 @@ ${result.join("\n")}`
3145
3335
  init_esm_shims();
3146
3336
  init_tool();
3147
3337
  import { execFile } from "child_process";
3338
+ import * as fs14 from "fs";
3148
3339
  import * as path15 from "path";
3149
3340
  var grepTool = {
3150
3341
  name: "grep",
3151
- description: `Search file contents using regex patterns. Uses ripgrep (rg) if available, falls back to grep. Supports context lines, file type filters, and multiple output modes.`,
3342
+ description: `Search file contents using regex patterns. Uses ripgrep (rg) if available, falls back to grep, then to a built-in Node.js search. Supports context lines, file type filters, and multiple output modes.`,
3152
3343
  inputSchema: {
3153
3344
  type: "object",
3154
3345
  properties: {
@@ -3178,16 +3369,20 @@ var grepTool = {
3178
3369
  const searchPath = path15.resolve(input3["path"] ? String(input3["path"]) : process.cwd());
3179
3370
  const outputMode = input3["output_mode"] || "files_with_matches";
3180
3371
  const headLimit = input3["head_limit"] || 0;
3372
+ const hasRg = await hasCommand("rg");
3373
+ const hasGrep = !hasRg && await hasCommand("grep");
3374
+ if (!hasRg && !hasGrep) {
3375
+ return builtinSearch(pattern, searchPath, input3, outputMode, headLimit);
3376
+ }
3377
+ const cmd = hasRg ? "rg" : "grep";
3181
3378
  const args = [];
3182
- const useRg = await hasCommand("rg");
3183
- const cmd = useRg ? "rg" : "grep";
3184
- if (!useRg) {
3379
+ if (!hasRg) {
3185
3380
  args.push("-r");
3186
3381
  }
3187
3382
  if (outputMode === "files_with_matches") {
3188
- args.push(useRg ? "-l" : "-l");
3383
+ args.push("-l");
3189
3384
  } else if (outputMode === "count") {
3190
- args.push(useRg ? "-c" : "-c");
3385
+ args.push("-c");
3191
3386
  }
3192
3387
  if (input3["-i"]) args.push("-i");
3193
3388
  if (input3["-n"] !== false && outputMode === "content") {
@@ -3196,16 +3391,16 @@ var grepTool = {
3196
3391
  if (input3["-C"]) args.push("-C", String(input3["-C"]));
3197
3392
  else if (input3["-A"]) args.push("-A", String(input3["-A"]));
3198
3393
  if (input3["-B"]) args.push("-B", String(input3["-B"]));
3199
- if (input3["multiline"] && useRg) {
3394
+ if (input3["multiline"] && hasRg) {
3200
3395
  args.push("-U", "--multiline-dotall");
3201
3396
  }
3202
- if (input3["type"] && useRg) {
3397
+ if (input3["type"] && hasRg) {
3203
3398
  args.push("--type", String(input3["type"]));
3204
3399
  }
3205
- if (input3["glob"] && useRg) {
3400
+ if (input3["glob"] && hasRg) {
3206
3401
  args.push("--glob", String(input3["glob"]));
3207
3402
  }
3208
- if (useRg) {
3403
+ if (hasRg) {
3209
3404
  args.push("--no-ignore-vcs");
3210
3405
  args.push("-g", "!node_modules");
3211
3406
  args.push("-g", "!.git");
@@ -3235,8 +3430,9 @@ var grepTool = {
3235
3430
  }
3236
3431
  };
3237
3432
  function hasCommand(cmd) {
3433
+ const checkCmd = process.platform === "win32" ? "where" : "which";
3238
3434
  return new Promise((resolve10) => {
3239
- execFile("which", [cmd], (err) => resolve10(!err));
3435
+ execFile(checkCmd, [cmd], (err) => resolve10(!err));
3240
3436
  });
3241
3437
  }
3242
3438
  function runCommand(cmd, args) {
@@ -3251,16 +3447,155 @@ function runCommand(cmd, args) {
3251
3447
  });
3252
3448
  });
3253
3449
  }
3450
+ var IGNORE_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "build", ".next", "__pycache__", ".cache", "coverage"]);
3451
+ var BINARY_EXTENSIONS = /* @__PURE__ */ new Set([".png", ".jpg", ".jpeg", ".gif", ".ico", ".woff", ".woff2", ".ttf", ".eot", ".pdf", ".zip", ".tar", ".gz", ".exe", ".dll", ".so", ".dylib"]);
3452
+ var TYPE_EXTENSIONS = {
3453
+ ts: [".ts", ".tsx"],
3454
+ js: [".js", ".jsx", ".mjs", ".cjs"],
3455
+ py: [".py"],
3456
+ java: [".java"],
3457
+ kt: [".kt", ".kts"],
3458
+ go: [".go"],
3459
+ rs: [".rs"],
3460
+ rb: [".rb"],
3461
+ css: [".css", ".scss", ".less"],
3462
+ html: [".html", ".htm"],
3463
+ json: [".json"],
3464
+ yaml: [".yaml", ".yml"],
3465
+ md: [".md"],
3466
+ xml: [".xml"]
3467
+ };
3468
+ async function builtinSearch(pattern, searchPath, input3, outputMode, headLimit) {
3469
+ const caseInsensitive = input3["-i"] === true;
3470
+ const showLineNumbers = input3["-n"] !== false && outputMode === "content";
3471
+ const contextBefore = Number(input3["-C"] || input3["-B"] || 0);
3472
+ const contextAfter = Number(input3["-C"] || input3["-A"] || 0);
3473
+ const typeFilter = input3["type"] ? String(input3["type"]) : void 0;
3474
+ const globFilter = input3["glob"] ? String(input3["glob"]) : void 0;
3475
+ let regex;
3476
+ try {
3477
+ regex = new RegExp(pattern, caseInsensitive ? "gi" : "g");
3478
+ } catch {
3479
+ return makeToolError(`Invalid regex pattern: ${pattern}`);
3480
+ }
3481
+ const files = collectFiles(searchPath, typeFilter, globFilter);
3482
+ const results = [];
3483
+ const fileCounts = /* @__PURE__ */ new Map();
3484
+ let entryCount = 0;
3485
+ for (const filePath of files) {
3486
+ if (headLimit > 0 && entryCount >= headLimit) break;
3487
+ let content;
3488
+ try {
3489
+ content = fs14.readFileSync(filePath, "utf-8");
3490
+ } catch {
3491
+ continue;
3492
+ }
3493
+ const lines = content.split("\n");
3494
+ const matchedLineIndices = /* @__PURE__ */ new Set();
3495
+ let fileMatchCount = 0;
3496
+ for (let i = 0; i < lines.length; i++) {
3497
+ if (regex.test(lines[i])) {
3498
+ matchedLineIndices.add(i);
3499
+ fileMatchCount++;
3500
+ }
3501
+ regex.lastIndex = 0;
3502
+ }
3503
+ if (fileMatchCount === 0) continue;
3504
+ if (outputMode === "files_with_matches") {
3505
+ results.push(filePath);
3506
+ entryCount++;
3507
+ } else if (outputMode === "count") {
3508
+ fileCounts.set(filePath, fileMatchCount);
3509
+ entryCount++;
3510
+ } else {
3511
+ const outputLines = /* @__PURE__ */ new Set();
3512
+ for (const idx of matchedLineIndices) {
3513
+ for (let j = Math.max(0, idx - contextBefore); j <= Math.min(lines.length - 1, idx + contextAfter); j++) {
3514
+ outputLines.add(j);
3515
+ }
3516
+ }
3517
+ const sortedIndices = [...outputLines].sort((a, b) => a - b);
3518
+ let lastIdx = -2;
3519
+ for (const idx of sortedIndices) {
3520
+ if (headLimit > 0 && entryCount >= headLimit) break;
3521
+ if (idx > lastIdx + 1 && lastIdx >= 0) {
3522
+ results.push("--");
3523
+ }
3524
+ const prefix = showLineNumbers ? `${filePath}:${idx + 1}:` : `${filePath}:`;
3525
+ results.push(`${prefix}${lines[idx]}`);
3526
+ entryCount++;
3527
+ lastIdx = idx;
3528
+ }
3529
+ }
3530
+ }
3531
+ if (outputMode === "count") {
3532
+ for (const [file, count] of fileCounts) {
3533
+ results.push(`${file}:${count}`);
3534
+ }
3535
+ }
3536
+ if (results.length === 0) {
3537
+ return makeToolResult(`No matches found for pattern: ${pattern}`);
3538
+ }
3539
+ return makeToolResult(results.join("\n"));
3540
+ }
3541
+ function collectFiles(dirPath, typeFilter, globFilter) {
3542
+ const files = [];
3543
+ const allowedExtensions = typeFilter && TYPE_EXTENSIONS[typeFilter] ? new Set(TYPE_EXTENSIONS[typeFilter]) : null;
3544
+ let globRegex = null;
3545
+ if (globFilter) {
3546
+ const escaped = globFilter.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
3547
+ globRegex = new RegExp(`^${escaped}$`);
3548
+ }
3549
+ function walk(dir) {
3550
+ let entries;
3551
+ try {
3552
+ entries = fs14.readdirSync(dir, { withFileTypes: true });
3553
+ } catch {
3554
+ return;
3555
+ }
3556
+ for (const entry of entries) {
3557
+ if (IGNORE_DIRS.has(entry.name)) continue;
3558
+ if (entry.name.startsWith(".") && entry.name !== ".") continue;
3559
+ const fullPath = path15.join(dir, entry.name);
3560
+ if (entry.isDirectory()) {
3561
+ walk(fullPath);
3562
+ } else if (entry.isFile()) {
3563
+ const ext = path15.extname(entry.name).toLowerCase();
3564
+ if (BINARY_EXTENSIONS.has(ext)) continue;
3565
+ if (allowedExtensions && !allowedExtensions.has(ext)) continue;
3566
+ if (globRegex && !globRegex.test(entry.name)) continue;
3567
+ files.push(fullPath);
3568
+ }
3569
+ }
3570
+ }
3571
+ try {
3572
+ const stat = fs14.statSync(dirPath);
3573
+ if (stat.isFile()) {
3574
+ return [dirPath];
3575
+ }
3576
+ } catch {
3577
+ return [];
3578
+ }
3579
+ walk(dirPath);
3580
+ return files;
3581
+ }
3254
3582
 
3255
3583
  // src/tools/bash.ts
3256
3584
  init_esm_shims();
3257
3585
  init_tool();
3258
3586
  import { exec as exec2, spawn } from "child_process";
3587
+ import * as os6 from "os";
3588
+ function getDefaultShell2() {
3589
+ if (os6.platform() === "win32") {
3590
+ return "powershell.exe";
3591
+ }
3592
+ return process.env["SHELL"] || "/bin/bash";
3593
+ }
3259
3594
  var backgroundTasks = /* @__PURE__ */ new Map();
3260
3595
  var taskCounter = 0;
3261
3596
  var bashTool = {
3262
3597
  name: "bash",
3263
- description: `Execute a bash command. Supports timeout (max 600s, default 120s) and background execution. The working directory persists between calls.`,
3598
+ description: `Execute a shell command. Supports timeout (max 600s, default 120s) and background execution. The working directory persists between calls. Uses the platform default shell (bash on Unix, cmd.exe on Windows).`,
3264
3599
  inputSchema: {
3265
3600
  type: "object",
3266
3601
  properties: {
@@ -3287,7 +3622,7 @@ var bashTool = {
3287
3622
  exec2(command, {
3288
3623
  timeout,
3289
3624
  maxBuffer: 10 * 1024 * 1024,
3290
- shell: process.env["SHELL"] || "/bin/bash",
3625
+ shell: getDefaultShell2(),
3291
3626
  cwd: process.cwd(),
3292
3627
  env: { ...process.env }
3293
3628
  }, (err, stdout, stderr) => {
@@ -3321,7 +3656,7 @@ ${stderr}` : ""
3321
3656
  function runBackgroundTask(command) {
3322
3657
  const taskId = `bg_${++taskCounter}`;
3323
3658
  const proc = spawn(command, {
3324
- shell: process.env["SHELL"] || "/bin/bash",
3659
+ shell: getDefaultShell2(),
3325
3660
  cwd: process.cwd(),
3326
3661
  env: { ...process.env },
3327
3662
  stdio: ["ignore", "pipe", "pipe"],
@@ -3351,7 +3686,7 @@ Use task_output tool to check results.`);
3351
3686
  // src/tools/list-dir.ts
3352
3687
  init_esm_shims();
3353
3688
  init_tool();
3354
- import * as fs14 from "fs";
3689
+ import * as fs15 from "fs";
3355
3690
  import * as path16 from "path";
3356
3691
  var listDirTool = {
3357
3692
  name: "list_dir",
@@ -3367,15 +3702,15 @@ var listDirTool = {
3367
3702
  readOnly: true,
3368
3703
  async execute(input3) {
3369
3704
  const dirPath = path16.resolve(input3["path"] ? String(input3["path"]) : process.cwd());
3370
- if (!fs14.existsSync(dirPath)) {
3705
+ if (!fs15.existsSync(dirPath)) {
3371
3706
  return makeToolError(`Directory not found: ${dirPath}`);
3372
3707
  }
3373
- const stat = fs14.statSync(dirPath);
3708
+ const stat = fs15.statSync(dirPath);
3374
3709
  if (!stat.isDirectory()) {
3375
3710
  return makeToolError(`Not a directory: ${dirPath}`);
3376
3711
  }
3377
3712
  try {
3378
- const entries = fs14.readdirSync(dirPath, { withFileTypes: true });
3713
+ const entries = fs15.readdirSync(dirPath, { withFileTypes: true });
3379
3714
  const IGNORE = /* @__PURE__ */ new Set([".git", "node_modules", ".DS_Store", "__pycache__", ".next", "dist", "build"]);
3380
3715
  const lines = [];
3381
3716
  const dirs = [];
@@ -3386,7 +3721,7 @@ var listDirTool = {
3386
3721
  dirs.push(`${entry.name}/`);
3387
3722
  } else if (entry.isSymbolicLink()) {
3388
3723
  try {
3389
- const target = fs14.readlinkSync(path16.join(dirPath, entry.name));
3724
+ const target = fs15.readlinkSync(path16.join(dirPath, entry.name));
3390
3725
  files.push(`${entry.name} -> ${target}`);
3391
3726
  } catch {
3392
3727
  files.push(`${entry.name} -> (broken link)`);
@@ -3598,7 +3933,7 @@ ${formatted}`);
3598
3933
  // src/tools/notebook-edit.ts
3599
3934
  init_esm_shims();
3600
3935
  init_tool();
3601
- import * as fs15 from "fs";
3936
+ import * as fs16 from "fs";
3602
3937
  import * as path17 from "path";
3603
3938
  var notebookEditTool = {
3604
3939
  name: "notebook_edit",
@@ -3622,11 +3957,11 @@ var notebookEditTool = {
3622
3957
  const newSource = String(input3["new_source"]);
3623
3958
  const cellType = input3["cell_type"] || "code";
3624
3959
  const editMode = input3["edit_mode"] || "replace";
3625
- if (!fs15.existsSync(nbPath)) {
3960
+ if (!fs16.existsSync(nbPath)) {
3626
3961
  return makeToolError(`Notebook not found: ${nbPath}`);
3627
3962
  }
3628
3963
  try {
3629
- const content = fs15.readFileSync(nbPath, "utf-8");
3964
+ const content = fs16.readFileSync(nbPath, "utf-8");
3630
3965
  const nb = JSON.parse(content);
3631
3966
  if (!nb.cells || !Array.isArray(nb.cells)) {
3632
3967
  return makeToolError("Invalid notebook format: no cells array");
@@ -3671,7 +4006,7 @@ var notebookEditTool = {
3671
4006
  default:
3672
4007
  return makeToolError(`Unknown edit_mode: ${editMode}`);
3673
4008
  }
3674
- fs15.writeFileSync(nbPath, JSON.stringify(nb, null, 1), "utf-8");
4009
+ fs16.writeFileSync(nbPath, JSON.stringify(nb, null, 1), "utf-8");
3675
4010
  return makeToolResult(`Notebook ${editMode}d cell in ${nbPath} (${nb.cells.length} cells total)`);
3676
4011
  } catch (err) {
3677
4012
  return makeToolError(`Notebook edit failed: ${err instanceof Error ? err.message : String(err)}`);