codesavant 1.1.0 → 1.2.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 (2) hide show
  1. package/dist/cli.js +142 -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
  // ============================================================
@@ -5584,7 +5641,39 @@ Format the findings clearly for the user. Include:
5584
5641
  - Ignoring subagent output and exploring from scratch
5585
5642
  - Continuing without specific focus areas
5586
5643
  - Exceeding 3 continuation rounds
5587
- - Passing vague instructions like "explore more"`;
5644
+ - Passing vague instructions like "explore more"
5645
+
5646
+ ## Project Creation Guide
5647
+
5648
+ When creating new projects, use these proven commands for each framework:
5649
+
5650
+ ### React Projects
5651
+ - **Vite + React + TypeScript** (RECOMMENDED): \`npm create vite@latest my-app -- --template react-ts\`
5652
+ - **Create React App**: \`npx create-react-app my-app --template typescript\`
5653
+
5654
+ ### Next.js Projects
5655
+ - \`npx create-next-app@latest my-app --typescript --tailwind --eslint --app --src-dir\`
5656
+
5657
+ ### Vue Projects
5658
+ - **Vite + Vue**: \`npm create vite@latest my-app -- --template vue-ts\`
5659
+ - **Vue CLI**: \`npx @vue/cli create my-app\`
5660
+
5661
+ ### Adding Tailwind CSS
5662
+ After project creation, install Tailwind:
5663
+ \`\`\`bash
5664
+ npm install -D tailwindcss postcss autoprefixer
5665
+ npx tailwindcss init -p
5666
+ \`\`\`
5667
+
5668
+ Then configure tailwind.config.js and add Tailwind directives to CSS.
5669
+
5670
+ ### Project Creation Rules
5671
+ 1. ALWAYS create projects in the current working directory or a subdirectory
5672
+ 2. NEVER use /tmp or system directories for project creation
5673
+ 3. Use the --template flag with Vite for TypeScript support
5674
+ 4. Run \`npm install\` after project creation if it fails during setup
5675
+ 5. If npm install fails, try: \`npm cache clean --force\` then retry
5676
+ 6. Check package.json exists before running npm commands`;
5588
5677
  async function loadConfig() {
5589
5678
  const configPath = path.join(os.homedir(), ".codesavant", "config.json");
5590
5679
  let fileConfig = {};
@@ -15631,6 +15720,20 @@ function validateWritePath(filePath, baseDir) {
15631
15720
  // src/tools/executor.ts
15632
15721
  var execAsync2 = promisify2(exec2);
15633
15722
  var executorConfig = null;
15723
+ function checkPathGuidance(targetPath) {
15724
+ const cwd = process.cwd();
15725
+ const absolutePath = path9.isAbsolute(targetPath) ? targetPath : path9.resolve(cwd, targetPath);
15726
+ const unexpectedPaths = ["/tmp", "/var/tmp", "/temp", "/var/folders"];
15727
+ for (const unexpectedPath of unexpectedPaths) {
15728
+ if (absolutePath.startsWith(unexpectedPath)) {
15729
+ 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.`;
15730
+ }
15731
+ }
15732
+ if (!absolutePath.startsWith(cwd) && !absolutePath.startsWith(path9.resolve(cwd))) {
15733
+ return `[PATH NOTE]: Writing to ${absolutePath} which is outside your working directory (${cwd}). This is allowed, but make sure this is intentional.`;
15734
+ }
15735
+ return null;
15736
+ }
15634
15737
  var subagentFindingsCache = /* @__PURE__ */ new Map();
15635
15738
  function getTaskKey(task) {
15636
15739
  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 +16118,20 @@ async function writeFile(input) {
16015
16118
  error: `Path validation failed: ${pathValidation.reason}`
16016
16119
  };
16017
16120
  }
16121
+ const pathGuidance = checkPathGuidance(filePath);
16018
16122
  const absolutePath = path9.resolve(filePath);
16019
16123
  await checkpointManager.backupFileBeforeWrite(absolutePath);
16020
16124
  await fs10.ensureDir(path9.dirname(absolutePath));
16021
16125
  await fs10.writeFile(absolutePath, content);
16126
+ let output = `Wrote ${content.length} bytes to ${filePath}`;
16127
+ if (pathGuidance) {
16128
+ output += `
16129
+
16130
+ ${pathGuidance}`;
16131
+ }
16022
16132
  return {
16023
16133
  success: true,
16024
- output: `Wrote ${content.length} bytes to ${filePath}`
16134
+ output
16025
16135
  };
16026
16136
  }
16027
16137
  async function editFile(input) {
@@ -30020,7 +30130,7 @@ function InputBoxView({
30020
30130
  ] }),
30021
30131
  /* @__PURE__ */ jsx4(Text4, { color: colors.primary, children: "Ctrl+C" }),
30022
30132
  /* @__PURE__ */ jsx4(Text4, { color: colors.muted, children: " cancel" }),
30023
- permissionMode && /* @__PURE__ */ jsxs4(Fragment2, { children: [
30133
+ currentPermissionMode && /* @__PURE__ */ jsxs4(Fragment2, { children: [
30024
30134
  /* @__PURE__ */ jsxs4(Text4, { color: colors.muted, children: [
30025
30135
  " ",
30026
30136
  icons.boxV,
@@ -30028,7 +30138,7 @@ function InputBoxView({
30028
30138
  ] }),
30029
30139
  /* @__PURE__ */ jsxs4(Text4, { color: colors.info, children: [
30030
30140
  "[",
30031
- permissionMode,
30141
+ currentPermissionMode,
30032
30142
  "]"
30033
30143
  ] })
30034
30144
  ] })
@@ -30061,6 +30171,7 @@ function App({
30061
30171
  const lastEscapeRef = useRef(0);
30062
30172
  const [renderedMessageCount, setRenderedMessageCount] = useState5(0);
30063
30173
  const permissionModes = ["prompt", "auto-edit", "auto-full", "deny"];
30174
+ const [currentPermissionMode2, setCurrentPermissionMode] = useState5(permissionMode);
30064
30175
  useEffect2(() => {
30065
30176
  if (sessionId2) actions.setSessionId(sessionId2);
30066
30177
  if (provider && model) actions.setProvider(provider, model);
@@ -30139,11 +30250,14 @@ function App({
30139
30250
  setHistorySearchMatch(null);
30140
30251
  return;
30141
30252
  }
30142
- if (key.shift && key.tab && onPermissionModeChange) {
30143
- const currentIndex = permissionModes.indexOf(permissionMode);
30253
+ if (key.shift && key.tab) {
30254
+ const currentIndex = permissionModes.indexOf(currentPermissionMode2);
30144
30255
  const nextIndex = (currentIndex + 1) % permissionModes.length;
30145
30256
  const nextMode = permissionModes[nextIndex];
30146
- onPermissionModeChange(nextMode);
30257
+ setCurrentPermissionMode(nextMode);
30258
+ if (onPermissionModeChange) {
30259
+ onPermissionModeChange(nextMode);
30260
+ }
30147
30261
  actions.addMessage({
30148
30262
  type: "system",
30149
30263
  content: `Permission mode: ${nextMode}`
@@ -30311,7 +30425,7 @@ function App({
30311
30425
  historyIndex: state.historyIndex,
30312
30426
  onHistoryNavigate: handleHistoryNavigate,
30313
30427
  theme,
30314
- permissionMode,
30428
+ permissionMode: currentPermissionMode2,
30315
30429
  historySearchMode,
30316
30430
  historySearchQuery,
30317
30431
  historySearchMatch,
@@ -30578,22 +30692,18 @@ function createInkREPL(replConfig) {
30578
30692
  }
30579
30693
  case "glob": {
30580
30694
  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 });
30695
+ const files = output ? output.split("\n").filter((l) => l.trim()) : [];
30696
+ return formatGlobResult(files, pattern, { collapsed: true });
30588
30697
  }
30589
30698
  case "bash": {
30699
+ const command = toolInput?.command || "bash command";
30590
30700
  const result = {
30591
30701
  exitCode: success ? 0 : 1,
30592
30702
  output: output.slice(0, 500),
30593
30703
  truncated: output.length > 500,
30594
30704
  totalLines: lineCount
30595
30705
  };
30596
- return formatBashResult(result, { collapsed: true });
30706
+ return formatBashResult(result, command, { collapsed: true });
30597
30707
  }
30598
30708
  default:
30599
30709
  if (success) {
@@ -31880,13 +31990,13 @@ Type /help for available commands.`);
31880
31990
  mcpTools: mcpToolCount,
31881
31991
  workingDir: projectPath
31882
31992
  });
31883
- let currentPermissionMode = agent.getPermissionManager().getMode();
31993
+ let currentPermissionMode2 = agent.getPermissionManager().getMode();
31884
31994
  appController = renderApp({
31885
31995
  sessionId: sessionId2,
31886
31996
  provider: defaultProvider?.name,
31887
31997
  model: defaultProvider?.model,
31888
31998
  welcomeMessage,
31889
- permissionMode: currentPermissionMode,
31999
+ permissionMode: currentPermissionMode2,
31890
32000
  onSubmit: (input) => {
31891
32001
  if (!isProcessing) {
31892
32002
  processAgentStream(input);
@@ -31922,7 +32032,7 @@ Type /help for available commands.`);
31922
32032
  const validModes = ["prompt", "auto-edit", "auto-full", "deny"];
31923
32033
  if (validModes.includes(mode)) {
31924
32034
  agent.getPermissionManager().setMode(mode);
31925
- currentPermissionMode = mode;
32035
+ currentPermissionMode2 = mode;
31926
32036
  }
31927
32037
  }
31928
32038
  });
@@ -32374,6 +32484,19 @@ program.argument("[prompt]", "Initial prompt to send").option("-p, --print", "Pr
32374
32484
  systemPrompt += "\n\n" + options.appendSystemPrompt;
32375
32485
  }
32376
32486
  }
32487
+ const workingDirContext = `
32488
+ ## Working Directory Context
32489
+
32490
+ **IMPORTANT**: Your current working directory is: ${projectPath}
32491
+
32492
+ When the user asks to create projects, files, or directories:
32493
+ - ALWAYS create them in or relative to this working directory (${projectPath})
32494
+ - Do NOT use /tmp or other system directories unless explicitly requested
32495
+ - Use relative paths when possible (e.g., "./my-project" instead of absolute paths)
32496
+ - If the user specifies a path, resolve it relative to the working directory
32497
+
32498
+ All file operations (read, write, edit, bash) execute in this directory by default.`;
32499
+ systemPrompt += workingDirContext;
32377
32500
  const allowedTools = options.allowedTools ? options.allowedTools.split(",").map((t) => t.trim()) : void 0;
32378
32501
  const disallowedTools = options.disallowedTools ? options.disallowedTools.split(",").map((t) => t.trim()) : void 0;
32379
32502
  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.0",
4
4
  "description": "Multi-provider AI coding assistant for your terminal",
5
5
  "type": "module",
6
6
  "bin": {