codesavant 1.1.0 → 1.2.2

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 (2) hide show
  1. package/dist/cli.js +150 -19
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -371,6 +371,63 @@ var init_knowledge_base = __esm({
371
371
  ],
372
372
  priority: 85
373
373
  },
374
+ {
375
+ id: "npm-network-error",
376
+ pattern: /npm ERR!.*network|ETIMEDOUT|ECONNREFUSED|ENOTFOUND.*registry|fetch failed/i,
377
+ category: "dependency",
378
+ subcategory: "network",
379
+ diagnosis: "npm network error. Cannot connect to the npm registry.",
380
+ suggestions: [
381
+ "Check your internet connection",
382
+ "Verify npm registry: npm config get registry",
383
+ "Try: npm config set registry https://registry.npmjs.org/",
384
+ "Check if behind a proxy and configure npm accordingly",
385
+ "Wait a moment and retry - registry may be temporarily unavailable"
386
+ ],
387
+ priority: 90
388
+ },
389
+ {
390
+ id: "npm-invalid-package-json",
391
+ pattern: /npm ERR!.*package\.json|Invalid package\.json|unexpected end of JSON|Unexpected token.*package\.json/i,
392
+ category: "dependency",
393
+ subcategory: "config",
394
+ diagnosis: "Invalid package.json file. The file contains syntax errors or is malformed.",
395
+ suggestions: [
396
+ "Validate package.json syntax at https://jsonlint.com/",
397
+ "Check for trailing commas, missing quotes, or incorrect brackets",
398
+ "Recreate package.json: npm init -y"
399
+ ],
400
+ priority: 95
401
+ },
402
+ {
403
+ id: "npx-package-not-found",
404
+ pattern: /npx.*command not found|npm ERR! could not determine executable|create-.*not found/i,
405
+ category: "dependency",
406
+ subcategory: "missing_package",
407
+ diagnosis: "npx could not find the package to execute.",
408
+ suggestions: [
409
+ "Check the package name is correct",
410
+ "Try installing globally first: npm install -g {package}",
411
+ "Clear npx cache: npx clear-npx-cache",
412
+ "Ensure npm is up to date: npm install -g npm"
413
+ ],
414
+ priority: 85
415
+ },
416
+ {
417
+ id: "create-app-failed",
418
+ pattern: /create-react-app.*failed|create-next-app.*failed|vite.*create.*failed|project.*creation.*failed/i,
419
+ category: "dependency",
420
+ subcategory: "project_creation",
421
+ diagnosis: "Project scaffolding failed. The project creation tool encountered an error.",
422
+ suggestions: [
423
+ "Try with a different directory name (avoid special characters)",
424
+ "Ensure you have write permissions in the target directory",
425
+ "Clear npm cache: npm cache clean --force",
426
+ "Check if Node.js version is compatible with the framework",
427
+ "Try creating in current directory: npx create-{tool}@latest ."
428
+ ],
429
+ priority: 92
430
+ },
374
431
  // ============================================================
375
432
  // GIT ERRORS (8 patterns)
376
433
  // ============================================================
@@ -5398,6 +5455,9 @@ var init_commands = __esm({
5398
5455
  // src/cli.ts
5399
5456
  import { Command } from "commander";
5400
5457
  import chalk20 from "chalk";
5458
+ import { readFileSync as readFileSync2 } from "fs";
5459
+ import { fileURLToPath } from "url";
5460
+ import { dirname, join as join3 } from "path";
5401
5461
 
5402
5462
  // src/config.ts
5403
5463
  import fs from "fs-extra";
@@ -5584,7 +5644,39 @@ Format the findings clearly for the user. Include:
5584
5644
  - Ignoring subagent output and exploring from scratch
5585
5645
  - Continuing without specific focus areas
5586
5646
  - Exceeding 3 continuation rounds
5587
- - Passing vague instructions like "explore more"`;
5647
+ - Passing vague instructions like "explore more"
5648
+
5649
+ ## Project Creation Guide
5650
+
5651
+ When creating new projects, use these proven commands for each framework:
5652
+
5653
+ ### React Projects
5654
+ - **Vite + React + TypeScript** (RECOMMENDED): \`npm create vite@latest my-app -- --template react-ts\`
5655
+ - **Create React App**: \`npx create-react-app my-app --template typescript\`
5656
+
5657
+ ### Next.js Projects
5658
+ - \`npx create-next-app@latest my-app --typescript --tailwind --eslint --app --src-dir\`
5659
+
5660
+ ### Vue Projects
5661
+ - **Vite + Vue**: \`npm create vite@latest my-app -- --template vue-ts\`
5662
+ - **Vue CLI**: \`npx @vue/cli create my-app\`
5663
+
5664
+ ### Adding Tailwind CSS
5665
+ After project creation, install Tailwind:
5666
+ \`\`\`bash
5667
+ npm install -D tailwindcss postcss autoprefixer
5668
+ npx tailwindcss init -p
5669
+ \`\`\`
5670
+
5671
+ Then configure tailwind.config.js and add Tailwind directives to CSS.
5672
+
5673
+ ### Project Creation Rules
5674
+ 1. ALWAYS create projects in the current working directory or a subdirectory
5675
+ 2. NEVER use /tmp or system directories for project creation
5676
+ 3. Use the --template flag with Vite for TypeScript support
5677
+ 4. Run \`npm install\` after project creation if it fails during setup
5678
+ 5. If npm install fails, try: \`npm cache clean --force\` then retry
5679
+ 6. Check package.json exists before running npm commands`;
5588
5680
  async function loadConfig() {
5589
5681
  const configPath = path.join(os.homedir(), ".codesavant", "config.json");
5590
5682
  let fileConfig = {};
@@ -15631,6 +15723,20 @@ function validateWritePath(filePath, baseDir) {
15631
15723
  // src/tools/executor.ts
15632
15724
  var execAsync2 = promisify2(exec2);
15633
15725
  var executorConfig = null;
15726
+ function checkPathGuidance(targetPath) {
15727
+ const cwd = process.cwd();
15728
+ const absolutePath = path9.isAbsolute(targetPath) ? targetPath : path9.resolve(cwd, targetPath);
15729
+ const unexpectedPaths = ["/tmp", "/var/tmp", "/temp", "/var/folders"];
15730
+ for (const unexpectedPath of unexpectedPaths) {
15731
+ if (absolutePath.startsWith(unexpectedPath)) {
15732
+ return `[PATH GUIDANCE]: You're writing to ${absolutePath} which is a temporary directory. Your working directory is ${cwd}. If you intended to create files in the project, use a relative path like "./" or specify the full path within ${cwd}. Files in /tmp may be deleted on system restart.`;
15733
+ }
15734
+ }
15735
+ if (!absolutePath.startsWith(cwd) && !absolutePath.startsWith(path9.resolve(cwd))) {
15736
+ return `[PATH NOTE]: Writing to ${absolutePath} which is outside your working directory (${cwd}). This is allowed, but make sure this is intentional.`;
15737
+ }
15738
+ return null;
15739
+ }
15634
15740
  var subagentFindingsCache = /* @__PURE__ */ new Map();
15635
15741
  function getTaskKey(task) {
15636
15742
  const baseTask = task.replace(/CONTINUATION \(Round \d+ of \d+\)/gi, "").replace(/## Previous Findings[\s\S]*?(?=##|$)/gi, "").replace(/## Focus Areas[\s\S]*?(?=##|$)/gi, "").trim().slice(0, 100);
@@ -16015,13 +16121,20 @@ async function writeFile(input) {
16015
16121
  error: `Path validation failed: ${pathValidation.reason}`
16016
16122
  };
16017
16123
  }
16124
+ const pathGuidance = checkPathGuidance(filePath);
16018
16125
  const absolutePath = path9.resolve(filePath);
16019
16126
  await checkpointManager.backupFileBeforeWrite(absolutePath);
16020
16127
  await fs10.ensureDir(path9.dirname(absolutePath));
16021
16128
  await fs10.writeFile(absolutePath, content);
16129
+ let output = `Wrote ${content.length} bytes to ${filePath}`;
16130
+ if (pathGuidance) {
16131
+ output += `
16132
+
16133
+ ${pathGuidance}`;
16134
+ }
16022
16135
  return {
16023
16136
  success: true,
16024
- output: `Wrote ${content.length} bytes to ${filePath}`
16137
+ output
16025
16138
  };
16026
16139
  }
16027
16140
  async function editFile(input) {
@@ -30061,6 +30174,7 @@ function App({
30061
30174
  const lastEscapeRef = useRef(0);
30062
30175
  const [renderedMessageCount, setRenderedMessageCount] = useState5(0);
30063
30176
  const permissionModes = ["prompt", "auto-edit", "auto-full", "deny"];
30177
+ const [currentPermissionMode, setCurrentPermissionMode] = useState5(permissionMode);
30064
30178
  useEffect2(() => {
30065
30179
  if (sessionId2) actions.setSessionId(sessionId2);
30066
30180
  if (provider && model) actions.setProvider(provider, model);
@@ -30139,11 +30253,14 @@ function App({
30139
30253
  setHistorySearchMatch(null);
30140
30254
  return;
30141
30255
  }
30142
- if (key.shift && key.tab && onPermissionModeChange) {
30143
- const currentIndex = permissionModes.indexOf(permissionMode);
30256
+ if (key.shift && key.tab) {
30257
+ const currentIndex = permissionModes.indexOf(currentPermissionMode);
30144
30258
  const nextIndex = (currentIndex + 1) % permissionModes.length;
30145
30259
  const nextMode = permissionModes[nextIndex];
30146
- onPermissionModeChange(nextMode);
30260
+ setCurrentPermissionMode(nextMode);
30261
+ if (onPermissionModeChange) {
30262
+ onPermissionModeChange(nextMode);
30263
+ }
30147
30264
  actions.addMessage({
30148
30265
  type: "system",
30149
30266
  content: `Permission mode: ${nextMode}`
@@ -30311,7 +30428,7 @@ function App({
30311
30428
  historyIndex: state.historyIndex,
30312
30429
  onHistoryNavigate: handleHistoryNavigate,
30313
30430
  theme,
30314
- permissionMode,
30431
+ permissionMode: currentPermissionMode,
30315
30432
  historySearchMode,
30316
30433
  historySearchQuery,
30317
30434
  historySearchMatch,
@@ -30578,22 +30695,18 @@ function createInkREPL(replConfig) {
30578
30695
  }
30579
30696
  case "glob": {
30580
30697
  const pattern = toolInput?.pattern || "*";
30581
- const matchCount = output ? output.split("\n").filter((l) => l.trim()).length : 0;
30582
- const result = {
30583
- matchCount,
30584
- pattern,
30585
- preview: output.slice(0, 300)
30586
- };
30587
- return formatGlobResult(result, { collapsed: true });
30698
+ const files = output ? output.split("\n").filter((l) => l.trim()) : [];
30699
+ return formatGlobResult(files, pattern, { collapsed: true });
30588
30700
  }
30589
30701
  case "bash": {
30702
+ const command = toolInput?.command || "bash command";
30590
30703
  const result = {
30591
30704
  exitCode: success ? 0 : 1,
30592
30705
  output: output.slice(0, 500),
30593
30706
  truncated: output.length > 500,
30594
30707
  totalLines: lineCount
30595
30708
  };
30596
- return formatBashResult(result, { collapsed: true });
30709
+ return formatBashResult(result, command, { collapsed: true });
30597
30710
  }
30598
30711
  default:
30599
30712
  if (success) {
@@ -32085,10 +32198,10 @@ async function detectCICommands(projectPath) {
32085
32198
  const fs26 = await import("fs-extra");
32086
32199
  const path27 = await import("path");
32087
32200
  const commands = [];
32088
- const packageJsonPath = path27.join(projectPath, "package.json");
32089
- if (await fs26.pathExists(packageJsonPath)) {
32201
+ const packageJsonPath2 = path27.join(projectPath, "package.json");
32202
+ if (await fs26.pathExists(packageJsonPath2)) {
32090
32203
  try {
32091
- const pkg = await fs26.readJson(packageJsonPath);
32204
+ const pkg = await fs26.readJson(packageJsonPath2);
32092
32205
  if (pkg.scripts?.build) {
32093
32206
  commands.push("npm run build");
32094
32207
  }
@@ -32121,7 +32234,7 @@ async function detectCICommands(projectPath) {
32121
32234
  if (await fs26.pathExists(path27.join(projectPath, "pyproject.toml")) || await fs26.pathExists(path27.join(projectPath, "setup.py"))) {
32122
32235
  commands.push("python -m pytest");
32123
32236
  }
32124
- if (commands.length === 0 && await fs26.pathExists(packageJsonPath)) {
32237
+ if (commands.length === 0 && await fs26.pathExists(packageJsonPath2)) {
32125
32238
  commands.push("npm run build");
32126
32239
  }
32127
32240
  return commands;
@@ -32217,6 +32330,11 @@ Fix all the issues to make the CI pass. Use the available tools to read files, e
32217
32330
  }
32218
32331
 
32219
32332
  // src/cli.ts
32333
+ var __filename = fileURLToPath(import.meta.url);
32334
+ var __dirname = dirname(__filename);
32335
+ var packageJsonPath = join3(__dirname, "..", "package.json");
32336
+ var packageJson = JSON.parse(readFileSync2(packageJsonPath, "utf-8"));
32337
+ var VERSION = packageJson.version;
32220
32338
  var MAX_STDIN_SIZE = 10 * 1024 * 1024;
32221
32339
  var MAX_STDIN_LINES = 1e5;
32222
32340
  async function readStdinInput(format, options) {
@@ -32268,7 +32386,7 @@ async function readStdinInput(format, options) {
32268
32386
  });
32269
32387
  }
32270
32388
  var program = new Command();
32271
- program.name("codesavant").description("AI coding assistant for your terminal").version("1.0.0").option("--verbose", "Enable verbose logging for debugging").option("--debug <categories>", 'Enable debug logging for specific categories (comma-separated: api,mcp,tool,provider,stream,session,context,permission,checkpoint,error,all). Use ! prefix to exclude: "all,!mcp"').option("--mcp-debug", "Enable MCP protocol-level debug logging").hook("preAction", (thisCommand) => {
32389
+ program.name("codesavant").description("AI coding assistant for your terminal").version(VERSION).option("--verbose", "Enable verbose logging for debugging").option("--debug <categories>", 'Enable debug logging for specific categories (comma-separated: api,mcp,tool,provider,stream,session,context,permission,checkpoint,error,all). Use ! prefix to exclude: "all,!mcp"').option("--mcp-debug", "Enable MCP protocol-level debug logging").hook("preAction", (thisCommand) => {
32272
32390
  const opts = thisCommand.opts();
32273
32391
  if (opts.debug) {
32274
32392
  setVerbose(true);
@@ -32374,6 +32492,19 @@ program.argument("[prompt]", "Initial prompt to send").option("-p, --print", "Pr
32374
32492
  systemPrompt += "\n\n" + options.appendSystemPrompt;
32375
32493
  }
32376
32494
  }
32495
+ const workingDirContext = `
32496
+ ## Working Directory Context
32497
+
32498
+ **IMPORTANT**: Your current working directory is: ${projectPath}
32499
+
32500
+ When the user asks to create projects, files, or directories:
32501
+ - ALWAYS create them in or relative to this working directory (${projectPath})
32502
+ - Do NOT use /tmp or other system directories unless explicitly requested
32503
+ - Use relative paths when possible (e.g., "./my-project" instead of absolute paths)
32504
+ - If the user specifies a path, resolve it relative to the working directory
32505
+
32506
+ All file operations (read, write, edit, bash) execute in this directory by default.`;
32507
+ systemPrompt += workingDirContext;
32377
32508
  const allowedTools = options.allowedTools ? options.allowedTools.split(",").map((t) => t.trim()) : void 0;
32378
32509
  const disallowedTools = options.disallowedTools ? options.disallowedTools.split(",").map((t) => t.trim()) : void 0;
32379
32510
  const maxTurns = options.maxTurns ? parseInt(options.maxTurns, 10) : void 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codesavant",
3
- "version": "1.1.0",
3
+ "version": "1.2.2",
4
4
  "description": "Multi-provider AI coding assistant for your terminal",
5
5
  "type": "module",
6
6
  "bin": {