@corbat-tech/coco 2.7.0 → 2.8.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.
package/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import { homedir } from 'os';
2
- import * as path15 from 'path';
3
- import path15__default, { dirname, join, basename, resolve } from 'path';
2
+ import * as path16 from 'path';
3
+ import path16__default, { dirname, join, basename, resolve } from 'path';
4
4
  import * as fs4 from 'fs';
5
5
  import fs4__default, { readFileSync, constants } from 'fs';
6
- import * as fs14 from 'fs/promises';
7
- import fs14__default, { readFile, access, readdir } from 'fs/promises';
6
+ import * as fs15 from 'fs/promises';
7
+ import fs15__default, { readFile, access, readdir } from 'fs/promises';
8
8
  import chalk3 from 'chalk';
9
9
  import * as p3 from '@clack/prompts';
10
10
  import { fileURLToPath } from 'url';
@@ -23,6 +23,7 @@ import 'http';
23
23
  import { GoogleGenerativeAI, FunctionCallingMode } from '@google/generative-ai';
24
24
  import JSON5 from 'json5';
25
25
  import 'events';
26
+ import 'minimatch';
26
27
  import { simpleGit } from 'simple-git';
27
28
  import hljs from 'highlight.js/lib/core';
28
29
  import bash from 'highlight.js/lib/languages/bash';
@@ -90,7 +91,7 @@ function loadGlobalCocoEnv() {
90
91
  try {
91
92
  const home = process.env.HOME || process.env.USERPROFILE || "";
92
93
  if (!home) return;
93
- const globalEnvPath = path15.join(home, ".coco", ".env");
94
+ const globalEnvPath = path16.join(home, ".coco", ".env");
94
95
  const content = fs4.readFileSync(globalEnvPath, "utf-8");
95
96
  for (const line of content.split("\n")) {
96
97
  const trimmed = line.trim();
@@ -255,10 +256,10 @@ function getAllowedPaths() {
255
256
  return [...sessionAllowedPaths];
256
257
  }
257
258
  function isWithinAllowedPath(absolutePath, operation) {
258
- const normalizedTarget = path15__default.normalize(absolutePath);
259
+ const normalizedTarget = path16__default.normalize(absolutePath);
259
260
  for (const entry of sessionAllowedPaths) {
260
- const normalizedAllowed = path15__default.normalize(entry.path);
261
- if (normalizedTarget === normalizedAllowed || normalizedTarget.startsWith(normalizedAllowed + path15__default.sep)) {
261
+ const normalizedAllowed = path16__default.normalize(entry.path);
262
+ if (normalizedTarget === normalizedAllowed || normalizedTarget.startsWith(normalizedAllowed + path16__default.sep)) {
262
263
  if (operation === "read") return true;
263
264
  if (entry.level === "write") return true;
264
265
  }
@@ -266,8 +267,8 @@ function isWithinAllowedPath(absolutePath, operation) {
266
267
  return false;
267
268
  }
268
269
  function addAllowedPathToSession(dirPath, level) {
269
- const absolute = path15__default.resolve(dirPath);
270
- if (sessionAllowedPaths.some((e) => path15__default.normalize(e.path) === path15__default.normalize(absolute))) {
270
+ const absolute = path16__default.resolve(dirPath);
271
+ if (sessionAllowedPaths.some((e) => path16__default.normalize(e.path) === path16__default.normalize(absolute))) {
271
272
  return;
272
273
  }
273
274
  sessionAllowedPaths.push({
@@ -278,14 +279,14 @@ function addAllowedPathToSession(dirPath, level) {
278
279
  }
279
280
  async function persistAllowedPath(dirPath, level) {
280
281
  if (!currentProjectPath) return;
281
- const absolute = path15__default.resolve(dirPath);
282
+ const absolute = path16__default.resolve(dirPath);
282
283
  const store = await loadStore();
283
284
  if (!store.projects[currentProjectPath]) {
284
285
  store.projects[currentProjectPath] = [];
285
286
  }
286
287
  const entries = store.projects[currentProjectPath];
287
- const normalized = path15__default.normalize(absolute);
288
- if (entries.some((e) => path15__default.normalize(e.path) === normalized)) {
288
+ const normalized = path16__default.normalize(absolute);
289
+ if (entries.some((e) => path16__default.normalize(e.path) === normalized)) {
289
290
  return;
290
291
  }
291
292
  entries.push({
@@ -297,7 +298,7 @@ async function persistAllowedPath(dirPath, level) {
297
298
  }
298
299
  async function loadStore() {
299
300
  try {
300
- const content = await fs14__default.readFile(STORE_FILE, "utf-8");
301
+ const content = await fs15__default.readFile(STORE_FILE, "utf-8");
301
302
  return { ...DEFAULT_STORE, ...JSON.parse(content) };
302
303
  } catch {
303
304
  return { ...DEFAULT_STORE };
@@ -305,8 +306,8 @@ async function loadStore() {
305
306
  }
306
307
  async function saveStore(store) {
307
308
  try {
308
- await fs14__default.mkdir(path15__default.dirname(STORE_FILE), { recursive: true });
309
- await fs14__default.writeFile(STORE_FILE, JSON.stringify(store, null, 2), "utf-8");
309
+ await fs15__default.mkdir(path16__default.dirname(STORE_FILE), { recursive: true });
310
+ await fs15__default.writeFile(STORE_FILE, JSON.stringify(store, null, 2), "utf-8");
310
311
  } catch {
311
312
  }
312
313
  }
@@ -314,7 +315,7 @@ var STORE_FILE, DEFAULT_STORE, sessionAllowedPaths, currentProjectPath;
314
315
  var init_allowed_paths = __esm({
315
316
  "src/tools/allowed-paths.ts"() {
316
317
  init_paths();
317
- STORE_FILE = path15__default.join(CONFIG_PATHS.home, "allowed-paths.json");
318
+ STORE_FILE = path16__default.join(CONFIG_PATHS.home, "allowed-paths.json");
318
319
  DEFAULT_STORE = {
319
320
  version: 1,
320
321
  projects: {}
@@ -395,7 +396,7 @@ __export(allow_path_prompt_exports, {
395
396
  promptAllowPath: () => promptAllowPath
396
397
  });
397
398
  async function promptAllowPath(dirPath) {
398
- const absolute = path15__default.resolve(dirPath);
399
+ const absolute = path16__default.resolve(dirPath);
399
400
  console.log();
400
401
  console.log(chalk3.yellow(" \u26A0 Access denied \u2014 path is outside the project directory"));
401
402
  console.log(chalk3.dim(` \u{1F4C1} ${absolute}`));
@@ -824,6 +825,9 @@ var TimeoutError = class extends CocoError {
824
825
  this.operation = options.operation;
825
826
  }
826
827
  };
828
+ function isCocoError(error) {
829
+ return error instanceof CocoError;
830
+ }
827
831
  function normalizeComplexity(value) {
828
832
  const normalized = value?.toLowerCase();
829
833
  if (normalized === "simple") return "simple";
@@ -1773,13 +1777,13 @@ function createSpecificationGenerator(llm, config) {
1773
1777
  return new SpecificationGenerator(llm, config);
1774
1778
  }
1775
1779
  function getPersistencePaths(projectPath) {
1776
- const baseDir = path15__default.join(projectPath, ".coco", "spec");
1780
+ const baseDir = path16__default.join(projectPath, ".coco", "spec");
1777
1781
  return {
1778
1782
  baseDir,
1779
- sessionFile: path15__default.join(baseDir, "discovery-session.json"),
1780
- specFile: path15__default.join(baseDir, "spec.md"),
1781
- conversationLog: path15__default.join(baseDir, "conversation.jsonl"),
1782
- checkpointFile: path15__default.join(baseDir, "checkpoint.json")
1783
+ sessionFile: path16__default.join(baseDir, "discovery-session.json"),
1784
+ specFile: path16__default.join(baseDir, "spec.md"),
1785
+ conversationLog: path16__default.join(baseDir, "conversation.jsonl"),
1786
+ checkpointFile: path16__default.join(baseDir, "checkpoint.json")
1783
1787
  };
1784
1788
  }
1785
1789
  var SessionPersistence = class {
@@ -1792,7 +1796,7 @@ var SessionPersistence = class {
1792
1796
  */
1793
1797
  async ensureDir() {
1794
1798
  try {
1795
- await fs14__default.mkdir(this.paths.baseDir, { recursive: true });
1799
+ await fs15__default.mkdir(this.paths.baseDir, { recursive: true });
1796
1800
  } catch {
1797
1801
  throw new FileSystemError(`Failed to create persistence directory: ${this.paths.baseDir}`, {
1798
1802
  path: this.paths.baseDir,
@@ -1807,7 +1811,7 @@ var SessionPersistence = class {
1807
1811
  await this.ensureDir();
1808
1812
  try {
1809
1813
  const data = JSON.stringify(session, null, 2);
1810
- await fs14__default.writeFile(this.paths.sessionFile, data, "utf-8");
1814
+ await fs15__default.writeFile(this.paths.sessionFile, data, "utf-8");
1811
1815
  } catch {
1812
1816
  throw new FileSystemError("Failed to save discovery session", {
1813
1817
  path: this.paths.sessionFile,
@@ -1820,7 +1824,7 @@ var SessionPersistence = class {
1820
1824
  */
1821
1825
  async loadSession() {
1822
1826
  try {
1823
- const data = await fs14__default.readFile(this.paths.sessionFile, "utf-8");
1827
+ const data = await fs15__default.readFile(this.paths.sessionFile, "utf-8");
1824
1828
  const parsed = JSON.parse(data);
1825
1829
  parsed.startedAt = new Date(parsed.startedAt);
1826
1830
  parsed.updatedAt = new Date(parsed.updatedAt);
@@ -1846,7 +1850,7 @@ var SessionPersistence = class {
1846
1850
  */
1847
1851
  async hasSession() {
1848
1852
  try {
1849
- await fs14__default.access(this.paths.sessionFile);
1853
+ await fs15__default.access(this.paths.sessionFile);
1850
1854
  return true;
1851
1855
  } catch {
1852
1856
  return false;
@@ -1857,7 +1861,7 @@ var SessionPersistence = class {
1857
1861
  */
1858
1862
  async deleteSession() {
1859
1863
  try {
1860
- await fs14__default.unlink(this.paths.sessionFile);
1864
+ await fs15__default.unlink(this.paths.sessionFile);
1861
1865
  } catch (error) {
1862
1866
  if (error.code !== "ENOENT") {
1863
1867
  throw new FileSystemError("Failed to delete discovery session", {
@@ -1873,7 +1877,7 @@ var SessionPersistence = class {
1873
1877
  async saveSpecification(content) {
1874
1878
  await this.ensureDir();
1875
1879
  try {
1876
- await fs14__default.writeFile(this.paths.specFile, content, "utf-8");
1880
+ await fs15__default.writeFile(this.paths.specFile, content, "utf-8");
1877
1881
  } catch {
1878
1882
  throw new FileSystemError("Failed to save specification", {
1879
1883
  path: this.paths.specFile,
@@ -1886,7 +1890,7 @@ var SessionPersistence = class {
1886
1890
  */
1887
1891
  async loadSpecification() {
1888
1892
  try {
1889
- return await fs14__default.readFile(this.paths.specFile, "utf-8");
1893
+ return await fs15__default.readFile(this.paths.specFile, "utf-8");
1890
1894
  } catch {
1891
1895
  return null;
1892
1896
  }
@@ -1902,7 +1906,7 @@ var SessionPersistence = class {
1902
1906
  content
1903
1907
  };
1904
1908
  try {
1905
- await fs14__default.appendFile(this.paths.conversationLog, JSON.stringify(entry) + "\n", "utf-8");
1909
+ await fs15__default.appendFile(this.paths.conversationLog, JSON.stringify(entry) + "\n", "utf-8");
1906
1910
  } catch {
1907
1911
  throw new FileSystemError("Failed to append to conversation log", {
1908
1912
  path: this.paths.conversationLog,
@@ -1915,7 +1919,7 @@ var SessionPersistence = class {
1915
1919
  */
1916
1920
  async loadConversationLog() {
1917
1921
  try {
1918
- const data = await fs14__default.readFile(this.paths.conversationLog, "utf-8");
1922
+ const data = await fs15__default.readFile(this.paths.conversationLog, "utf-8");
1919
1923
  const lines = data.trim().split("\n");
1920
1924
  return lines.filter((line) => line.trim()).map((line) => JSON.parse(line));
1921
1925
  } catch {
@@ -1929,7 +1933,7 @@ var SessionPersistence = class {
1929
1933
  await this.ensureDir();
1930
1934
  try {
1931
1935
  const data = JSON.stringify(checkpoint, null, 2);
1932
- await fs14__default.writeFile(this.paths.checkpointFile, data, "utf-8");
1936
+ await fs15__default.writeFile(this.paths.checkpointFile, data, "utf-8");
1933
1937
  } catch {
1934
1938
  throw new FileSystemError("Failed to save checkpoint", {
1935
1939
  path: this.paths.checkpointFile,
@@ -1942,7 +1946,7 @@ var SessionPersistence = class {
1942
1946
  */
1943
1947
  async loadCheckpoint() {
1944
1948
  try {
1945
- const data = await fs14__default.readFile(this.paths.checkpointFile, "utf-8");
1949
+ const data = await fs15__default.readFile(this.paths.checkpointFile, "utf-8");
1946
1950
  const parsed = JSON.parse(data);
1947
1951
  parsed.timestamp = new Date(parsed.timestamp);
1948
1952
  return parsed;
@@ -1955,7 +1959,7 @@ var SessionPersistence = class {
1955
1959
  */
1956
1960
  async clearAll() {
1957
1961
  try {
1958
- await fs14__default.rm(this.paths.baseDir, { recursive: true, force: true });
1962
+ await fs15__default.rm(this.paths.baseDir, { recursive: true, force: true });
1959
1963
  } catch (error) {
1960
1964
  if (error.code !== "ENOENT") {
1961
1965
  throw new FileSystemError("Failed to clear persistence data", {
@@ -3809,8 +3813,8 @@ var OrchestrateExecutor = class {
3809
3813
  }
3810
3814
  async loadSpecification(projectPath) {
3811
3815
  try {
3812
- const jsonPath = path15__default.join(projectPath, ".coco", "spec", "spec.json");
3813
- const jsonContent = await fs14__default.readFile(jsonPath, "utf-8");
3816
+ const jsonPath = path16__default.join(projectPath, ".coco", "spec", "spec.json");
3817
+ const jsonContent = await fs15__default.readFile(jsonPath, "utf-8");
3814
3818
  return JSON.parse(jsonContent);
3815
3819
  } catch {
3816
3820
  return this.createMinimalSpec(projectPath);
@@ -3821,7 +3825,7 @@ var OrchestrateExecutor = class {
3821
3825
  version: "1.0.0",
3822
3826
  generatedAt: /* @__PURE__ */ new Date(),
3823
3827
  overview: {
3824
- name: path15__default.basename(projectPath),
3828
+ name: path16__default.basename(projectPath),
3825
3829
  description: "Project specification",
3826
3830
  goals: [],
3827
3831
  targetUsers: ["developers"],
@@ -3848,53 +3852,53 @@ var OrchestrateExecutor = class {
3848
3852
  };
3849
3853
  }
3850
3854
  async saveArchitecture(projectPath, architecture) {
3851
- const dir = path15__default.join(projectPath, ".coco", "architecture");
3852
- await fs14__default.mkdir(dir, { recursive: true });
3853
- const mdPath = path15__default.join(dir, "ARCHITECTURE.md");
3854
- await fs14__default.writeFile(mdPath, generateArchitectureMarkdown(architecture), "utf-8");
3855
- const jsonPath = path15__default.join(dir, "architecture.json");
3856
- await fs14__default.writeFile(jsonPath, JSON.stringify(architecture, null, 2), "utf-8");
3855
+ const dir = path16__default.join(projectPath, ".coco", "architecture");
3856
+ await fs15__default.mkdir(dir, { recursive: true });
3857
+ const mdPath = path16__default.join(dir, "ARCHITECTURE.md");
3858
+ await fs15__default.writeFile(mdPath, generateArchitectureMarkdown(architecture), "utf-8");
3859
+ const jsonPath = path16__default.join(dir, "architecture.json");
3860
+ await fs15__default.writeFile(jsonPath, JSON.stringify(architecture, null, 2), "utf-8");
3857
3861
  return mdPath;
3858
3862
  }
3859
3863
  async saveADRs(projectPath, adrs) {
3860
- const dir = path15__default.join(projectPath, ".coco", "architecture", "adrs");
3861
- await fs14__default.mkdir(dir, { recursive: true });
3864
+ const dir = path16__default.join(projectPath, ".coco", "architecture", "adrs");
3865
+ await fs15__default.mkdir(dir, { recursive: true });
3862
3866
  const paths = [];
3863
- const indexPath = path15__default.join(dir, "README.md");
3864
- await fs14__default.writeFile(indexPath, generateADRIndexMarkdown(adrs), "utf-8");
3867
+ const indexPath = path16__default.join(dir, "README.md");
3868
+ await fs15__default.writeFile(indexPath, generateADRIndexMarkdown(adrs), "utf-8");
3865
3869
  paths.push(indexPath);
3866
3870
  for (const adr of adrs) {
3867
3871
  const filename = getADRFilename(adr);
3868
- const adrPath = path15__default.join(dir, filename);
3869
- await fs14__default.writeFile(adrPath, generateADRMarkdown(adr), "utf-8");
3872
+ const adrPath = path16__default.join(dir, filename);
3873
+ await fs15__default.writeFile(adrPath, generateADRMarkdown(adr), "utf-8");
3870
3874
  paths.push(adrPath);
3871
3875
  }
3872
3876
  return paths;
3873
3877
  }
3874
3878
  async saveBacklog(projectPath, backlogResult) {
3875
- const dir = path15__default.join(projectPath, ".coco", "planning");
3876
- await fs14__default.mkdir(dir, { recursive: true });
3877
- const mdPath = path15__default.join(dir, "BACKLOG.md");
3878
- await fs14__default.writeFile(mdPath, generateBacklogMarkdown(backlogResult.backlog), "utf-8");
3879
- const jsonPath = path15__default.join(dir, "backlog.json");
3880
- await fs14__default.writeFile(jsonPath, JSON.stringify(backlogResult, null, 2), "utf-8");
3879
+ const dir = path16__default.join(projectPath, ".coco", "planning");
3880
+ await fs15__default.mkdir(dir, { recursive: true });
3881
+ const mdPath = path16__default.join(dir, "BACKLOG.md");
3882
+ await fs15__default.writeFile(mdPath, generateBacklogMarkdown(backlogResult.backlog), "utf-8");
3883
+ const jsonPath = path16__default.join(dir, "backlog.json");
3884
+ await fs15__default.writeFile(jsonPath, JSON.stringify(backlogResult, null, 2), "utf-8");
3881
3885
  return mdPath;
3882
3886
  }
3883
3887
  async saveSprint(projectPath, sprint, backlogResult) {
3884
- const dir = path15__default.join(projectPath, ".coco", "planning", "sprints");
3885
- await fs14__default.mkdir(dir, { recursive: true });
3888
+ const dir = path16__default.join(projectPath, ".coco", "planning", "sprints");
3889
+ await fs15__default.mkdir(dir, { recursive: true });
3886
3890
  const filename = `${sprint.id}.md`;
3887
- const sprintPath = path15__default.join(dir, filename);
3888
- await fs14__default.writeFile(sprintPath, generateSprintMarkdown(sprint, backlogResult.backlog), "utf-8");
3889
- const jsonPath = path15__default.join(dir, `${sprint.id}.json`);
3890
- await fs14__default.writeFile(jsonPath, JSON.stringify(sprint, null, 2), "utf-8");
3891
+ const sprintPath = path16__default.join(dir, filename);
3892
+ await fs15__default.writeFile(sprintPath, generateSprintMarkdown(sprint, backlogResult.backlog), "utf-8");
3893
+ const jsonPath = path16__default.join(dir, `${sprint.id}.json`);
3894
+ await fs15__default.writeFile(jsonPath, JSON.stringify(sprint, null, 2), "utf-8");
3891
3895
  return sprintPath;
3892
3896
  }
3893
3897
  async saveDiagram(projectPath, id, mermaid) {
3894
- const dir = path15__default.join(projectPath, ".coco", "architecture", "diagrams");
3895
- await fs14__default.mkdir(dir, { recursive: true });
3896
- const diagramPath = path15__default.join(dir, `${id}.mmd`);
3897
- await fs14__default.writeFile(diagramPath, mermaid, "utf-8");
3898
+ const dir = path16__default.join(projectPath, ".coco", "architecture", "diagrams");
3899
+ await fs15__default.mkdir(dir, { recursive: true });
3900
+ const diagramPath = path16__default.join(dir, `${id}.mmd`);
3901
+ await fs15__default.writeFile(diagramPath, mermaid, "utf-8");
3898
3902
  return diagramPath;
3899
3903
  }
3900
3904
  };
@@ -4049,10 +4053,10 @@ var CoverageAnalyzer = class {
4049
4053
  join(this.projectPath, ".coverage", "coverage-summary.json"),
4050
4054
  join(this.projectPath, "coverage", "lcov-report", "coverage-summary.json")
4051
4055
  ];
4052
- for (const path38 of possiblePaths) {
4056
+ for (const path39 of possiblePaths) {
4053
4057
  try {
4054
- await access(path38, constants.R_OK);
4055
- const content = await readFile(path38, "utf-8");
4058
+ await access(path39, constants.R_OK);
4059
+ const content = await readFile(path39, "utf-8");
4056
4060
  const report = JSON.parse(content);
4057
4061
  return parseCoverageSummary(report);
4058
4062
  } catch {
@@ -4771,7 +4775,7 @@ var BuildVerifier = class {
4771
4775
  async verifyTypes() {
4772
4776
  const startTime = Date.now();
4773
4777
  try {
4774
- const hasTsConfig = await this.fileExists(path15.join(this.projectPath, "tsconfig.json"));
4778
+ const hasTsConfig = await this.fileExists(path16.join(this.projectPath, "tsconfig.json"));
4775
4779
  if (!hasTsConfig) {
4776
4780
  return {
4777
4781
  success: true,
@@ -4821,8 +4825,8 @@ var BuildVerifier = class {
4821
4825
  */
4822
4826
  async detectBuildCommand() {
4823
4827
  try {
4824
- const packageJsonPath = path15.join(this.projectPath, "package.json");
4825
- const content = await fs14.readFile(packageJsonPath, "utf-8");
4828
+ const packageJsonPath = path16.join(this.projectPath, "package.json");
4829
+ const content = await fs15.readFile(packageJsonPath, "utf-8");
4826
4830
  const packageJson = JSON.parse(content);
4827
4831
  if (packageJson.scripts?.build) {
4828
4832
  return "npm run build";
@@ -4898,7 +4902,7 @@ var BuildVerifier = class {
4898
4902
  */
4899
4903
  async fileExists(filePath) {
4900
4904
  try {
4901
- await fs14.access(filePath);
4905
+ await fs15.access(filePath);
4902
4906
  return true;
4903
4907
  } catch {
4904
4908
  return false;
@@ -6444,9 +6448,9 @@ function detectProjectLanguage(files) {
6444
6448
  return { language: dominant, confidence, evidence };
6445
6449
  }
6446
6450
  function getFileExtension(filePath) {
6447
- const base = path15.basename(filePath);
6451
+ const base = path16.basename(filePath);
6448
6452
  if (base.endsWith(".d.ts")) return ".d.ts";
6449
- return path15.extname(filePath).toLowerCase();
6453
+ return path16.extname(filePath).toLowerCase();
6450
6454
  }
6451
6455
  function buildEvidence(dominant, counts, totalSourceFiles, files) {
6452
6456
  const evidence = [];
@@ -6454,7 +6458,7 @@ function buildEvidence(dominant, counts, totalSourceFiles, files) {
6454
6458
  evidence.push(`${dominantCount} of ${totalSourceFiles} source files are ${dominant}`);
6455
6459
  const configFiles = ["tsconfig.json", "pom.xml", "build.gradle", "Cargo.toml", "go.mod"];
6456
6460
  for (const cfg of configFiles) {
6457
- if (files.some((f) => path15.basename(f) === cfg)) {
6461
+ if (files.some((f) => path16.basename(f) === cfg)) {
6458
6462
  evidence.push(`Found ${cfg}`);
6459
6463
  }
6460
6464
  }
@@ -8166,7 +8170,7 @@ function setupFileLogging(logger, logDir, name) {
8166
8170
  if (!fs4__default.existsSync(logDir)) {
8167
8171
  fs4__default.mkdirSync(logDir, { recursive: true });
8168
8172
  }
8169
- const logFile = path15__default.join(logDir, `${name}.log`);
8173
+ const logFile = path16__default.join(logDir, `${name}.log`);
8170
8174
  logger.attachTransport((logObj) => {
8171
8175
  const line = JSON.stringify(logObj) + "\n";
8172
8176
  fs4__default.appendFileSync(logFile, line);
@@ -8190,6 +8194,14 @@ function extractQuotedPath(msg) {
8190
8194
  function humanizeError(message, toolName) {
8191
8195
  const msg = message.trim();
8192
8196
  if (!msg) return msg;
8197
+ if (/Use (glob|list_dir|read_file|git_init|git_status|git_add|git_commit|git_log|git_branch|git_checkout|git_push|git_pull|web_search|inspect_schema|list_checkpoints|command_exists|edit_file|run_linter|run_tests|run_script|bash_exec)\b/.test(
8198
+ msg
8199
+ )) {
8200
+ return msg;
8201
+ }
8202
+ if (/run git_init\b/.test(msg)) {
8203
+ return msg;
8204
+ }
8193
8205
  if (/ECONNREFUSED/i.test(msg)) {
8194
8206
  return "Connection refused \u2014 the server may not be running";
8195
8207
  }
@@ -8211,13 +8223,22 @@ function humanizeError(message, toolName) {
8211
8223
  if (/fetch failed|network error|Failed to fetch/i.test(msg)) {
8212
8224
  return "Network request failed \u2014 check your internet connection";
8213
8225
  }
8226
+ if (/File not found:/.test(msg) && /Did you mean/.test(msg)) {
8227
+ return msg;
8228
+ }
8229
+ if (/Directory not found:/.test(msg) && /Did you mean/.test(msg)) {
8230
+ return msg;
8231
+ }
8232
+ if (/^HTTP \d{3}:/.test(msg) && /Try/.test(msg)) {
8233
+ return msg;
8234
+ }
8214
8235
  if (/ENOENT/i.test(msg)) {
8215
- const path38 = extractQuotedPath(msg);
8216
- return path38 ? `File or directory not found: ${path38}` : "File or directory not found";
8236
+ const path39 = extractQuotedPath(msg);
8237
+ return path39 ? `File or directory not found: ${path39}` : "File or directory not found";
8217
8238
  }
8218
8239
  if (/EACCES/i.test(msg)) {
8219
- const path38 = extractQuotedPath(msg);
8220
- return path38 ? `Permission denied: ${path38}` : "Permission denied \u2014 check file permissions";
8240
+ const path39 = extractQuotedPath(msg);
8241
+ return path39 ? `Permission denied: ${path39}` : "Permission denied \u2014 check file permissions";
8221
8242
  }
8222
8243
  if (/EISDIR/i.test(msg)) {
8223
8244
  return "Expected a file but found a directory at the specified path";
@@ -8300,6 +8321,12 @@ function humanizeError(message, toolName) {
8300
8321
  if (/invalid.*api.?key|api.?key.*invalid|api.?key.*not.*found/i.test(msg)) {
8301
8322
  return "Invalid or missing API key \u2014 check your provider credentials";
8302
8323
  }
8324
+ if (/TS\d{4}:/.test(msg)) {
8325
+ return `TypeScript error \u2014 check the referenced file and line number. ${msg}`;
8326
+ }
8327
+ if (/SQLITE_ERROR/i.test(msg)) {
8328
+ return `Database error \u2014 use inspect_schema to verify the table structure. ${msg}`;
8329
+ }
8303
8330
  return msg;
8304
8331
  }
8305
8332
 
@@ -8407,6 +8434,14 @@ var ToolRegistry = class {
8407
8434
  if (allUndefined && error.issues.length > 1) {
8408
8435
  errorMessage += ". All parameters are missing \u2014 this is likely a JSON serialization error on our side. Please retry with the same arguments.";
8409
8436
  }
8437
+ } else if (isCocoError(error)) {
8438
+ const causeMsg = error.cause instanceof Error ? error.cause.message : "";
8439
+ const combined = causeMsg && !error.message.includes(causeMsg) ? `${error.message} \u2014 ${causeMsg}` : error.message;
8440
+ errorMessage = humanizeError(combined, name);
8441
+ if (error.suggestion && !errorMessage.includes(error.suggestion)) {
8442
+ errorMessage += `
8443
+ Suggestion: ${error.suggestion}`;
8444
+ }
8410
8445
  } else {
8411
8446
  const rawMessage = error instanceof Error ? error.message : String(error);
8412
8447
  errorMessage = humanizeError(rawMessage, name);
@@ -9688,14 +9723,14 @@ var CompleteExecutor = class {
9688
9723
  */
9689
9724
  async checkpoint(context) {
9690
9725
  if (this.checkpointState && this.currentSprint) {
9691
- const checkpointPath = path15__default.join(
9726
+ const checkpointPath = path16__default.join(
9692
9727
  context.projectPath,
9693
9728
  ".coco",
9694
9729
  "checkpoints",
9695
9730
  `complete-${this.currentSprint.id}.json`
9696
9731
  );
9697
- await fs14__default.mkdir(path15__default.dirname(checkpointPath), { recursive: true });
9698
- await fs14__default.writeFile(checkpointPath, JSON.stringify(this.checkpointState, null, 2), "utf-8");
9732
+ await fs15__default.mkdir(path16__default.dirname(checkpointPath), { recursive: true });
9733
+ await fs15__default.writeFile(checkpointPath, JSON.stringify(this.checkpointState, null, 2), "utf-8");
9699
9734
  }
9700
9735
  return {
9701
9736
  phase: "complete",
@@ -9715,13 +9750,13 @@ var CompleteExecutor = class {
9715
9750
  const sprintId = checkpoint.resumePoint;
9716
9751
  if (sprintId === "start") return;
9717
9752
  try {
9718
- const checkpointPath = path15__default.join(
9753
+ const checkpointPath = path16__default.join(
9719
9754
  context.projectPath,
9720
9755
  ".coco",
9721
9756
  "checkpoints",
9722
9757
  `complete-${sprintId}.json`
9723
9758
  );
9724
- const content = await fs14__default.readFile(checkpointPath, "utf-8");
9759
+ const content = await fs15__default.readFile(checkpointPath, "utf-8");
9725
9760
  this.checkpointState = JSON.parse(content);
9726
9761
  this.completedTaskIds = new Set(this.checkpointState.completedTaskIds);
9727
9762
  } catch {
@@ -9968,14 +10003,14 @@ var CompleteExecutor = class {
9968
10003
  };
9969
10004
  const saveFiles = async (files) => {
9970
10005
  for (const file of files) {
9971
- const filePath = path15__default.join(context.projectPath, file.path);
9972
- const dir = path15__default.dirname(filePath);
9973
- await fs14__default.mkdir(dir, { recursive: true });
10006
+ const filePath = path16__default.join(context.projectPath, file.path);
10007
+ const dir = path16__default.dirname(filePath);
10008
+ await fs15__default.mkdir(dir, { recursive: true });
9974
10009
  if (file.action === "delete") {
9975
- await fs14__default.unlink(filePath).catch(() => {
10010
+ await fs15__default.unlink(filePath).catch(() => {
9976
10011
  });
9977
10012
  } else {
9978
- await fs14__default.writeFile(filePath, file.content, "utf-8");
10013
+ await fs15__default.writeFile(filePath, file.content, "utf-8");
9979
10014
  }
9980
10015
  }
9981
10016
  };
@@ -10101,8 +10136,8 @@ var CompleteExecutor = class {
10101
10136
  */
10102
10137
  async loadBacklog(projectPath) {
10103
10138
  try {
10104
- const backlogPath = path15__default.join(projectPath, ".coco", "planning", "backlog.json");
10105
- const content = await fs14__default.readFile(backlogPath, "utf-8");
10139
+ const backlogPath = path16__default.join(projectPath, ".coco", "planning", "backlog.json");
10140
+ const content = await fs15__default.readFile(backlogPath, "utf-8");
10106
10141
  const data = JSON.parse(content);
10107
10142
  return data.backlog;
10108
10143
  } catch {
@@ -10114,12 +10149,12 @@ var CompleteExecutor = class {
10114
10149
  */
10115
10150
  async loadCurrentSprint(projectPath) {
10116
10151
  try {
10117
- const sprintsDir = path15__default.join(projectPath, ".coco", "planning", "sprints");
10118
- const files = await fs14__default.readdir(sprintsDir);
10152
+ const sprintsDir = path16__default.join(projectPath, ".coco", "planning", "sprints");
10153
+ const files = await fs15__default.readdir(sprintsDir);
10119
10154
  const jsonFiles = files.filter((f) => f.endsWith(".json"));
10120
10155
  if (jsonFiles.length === 0) return null;
10121
- const sprintPath = path15__default.join(sprintsDir, jsonFiles[0] || "");
10122
- const content = await fs14__default.readFile(sprintPath, "utf-8");
10156
+ const sprintPath = path16__default.join(sprintsDir, jsonFiles[0] || "");
10157
+ const content = await fs15__default.readFile(sprintPath, "utf-8");
10123
10158
  const sprint = JSON.parse(content);
10124
10159
  sprint.startDate = new Date(sprint.startDate);
10125
10160
  return sprint;
@@ -10131,12 +10166,12 @@ var CompleteExecutor = class {
10131
10166
  * Save sprint results
10132
10167
  */
10133
10168
  async saveSprintResults(projectPath, result) {
10134
- const resultsDir = path15__default.join(projectPath, ".coco", "results");
10135
- await fs14__default.mkdir(resultsDir, { recursive: true });
10136
- const resultsPath = path15__default.join(resultsDir, `${result.sprintId}-results.json`);
10137
- await fs14__default.writeFile(resultsPath, JSON.stringify(result, null, 2), "utf-8");
10138
- const mdPath = path15__default.join(resultsDir, `${result.sprintId}-results.md`);
10139
- await fs14__default.writeFile(mdPath, this.generateResultsMarkdown(result), "utf-8");
10169
+ const resultsDir = path16__default.join(projectPath, ".coco", "results");
10170
+ await fs15__default.mkdir(resultsDir, { recursive: true });
10171
+ const resultsPath = path16__default.join(resultsDir, `${result.sprintId}-results.json`);
10172
+ await fs15__default.writeFile(resultsPath, JSON.stringify(result, null, 2), "utf-8");
10173
+ const mdPath = path16__default.join(resultsDir, `${result.sprintId}-results.md`);
10174
+ await fs15__default.writeFile(mdPath, this.generateResultsMarkdown(result), "utf-8");
10140
10175
  return resultsPath;
10141
10176
  }
10142
10177
  /**
@@ -11360,9 +11395,9 @@ var OutputExecutor = class {
11360
11395
  const cicdGenerator = new CICDGenerator(metadata, cicdConfig);
11361
11396
  const cicdFiles = cicdGenerator.generate();
11362
11397
  for (const file of cicdFiles) {
11363
- const filePath = path15__default.join(context.projectPath, file.path);
11364
- await this.ensureDir(path15__default.dirname(filePath));
11365
- await fs14__default.writeFile(filePath, file.content, "utf-8");
11398
+ const filePath = path16__default.join(context.projectPath, file.path);
11399
+ await this.ensureDir(path16__default.dirname(filePath));
11400
+ await fs15__default.writeFile(filePath, file.content, "utf-8");
11366
11401
  artifacts.push({
11367
11402
  type: "cicd",
11368
11403
  path: filePath,
@@ -11372,16 +11407,16 @@ var OutputExecutor = class {
11372
11407
  if (this.config.docker.enabled) {
11373
11408
  const dockerGenerator = new DockerGenerator(metadata);
11374
11409
  const dockerfile2 = dockerGenerator.generateDockerfile();
11375
- const dockerfilePath = path15__default.join(context.projectPath, "Dockerfile");
11376
- await fs14__default.writeFile(dockerfilePath, dockerfile2, "utf-8");
11410
+ const dockerfilePath = path16__default.join(context.projectPath, "Dockerfile");
11411
+ await fs15__default.writeFile(dockerfilePath, dockerfile2, "utf-8");
11377
11412
  artifacts.push({
11378
11413
  type: "deployment",
11379
11414
  path: dockerfilePath,
11380
11415
  description: "Dockerfile"
11381
11416
  });
11382
11417
  const dockerignore = dockerGenerator.generateDockerignore();
11383
- const dockerignorePath = path15__default.join(context.projectPath, ".dockerignore");
11384
- await fs14__default.writeFile(dockerignorePath, dockerignore, "utf-8");
11418
+ const dockerignorePath = path16__default.join(context.projectPath, ".dockerignore");
11419
+ await fs15__default.writeFile(dockerignorePath, dockerignore, "utf-8");
11385
11420
  artifacts.push({
11386
11421
  type: "deployment",
11387
11422
  path: dockerignorePath,
@@ -11389,8 +11424,8 @@ var OutputExecutor = class {
11389
11424
  });
11390
11425
  if (this.config.docker.compose) {
11391
11426
  const compose = dockerGenerator.generateDockerCompose();
11392
- const composePath = path15__default.join(context.projectPath, "docker-compose.yml");
11393
- await fs14__default.writeFile(composePath, compose, "utf-8");
11427
+ const composePath = path16__default.join(context.projectPath, "docker-compose.yml");
11428
+ await fs15__default.writeFile(composePath, compose, "utf-8");
11394
11429
  artifacts.push({
11395
11430
  type: "deployment",
11396
11431
  path: composePath,
@@ -11401,8 +11436,8 @@ var OutputExecutor = class {
11401
11436
  const docsGenerator = new DocsGenerator(metadata);
11402
11437
  const docs = docsGenerator.generate();
11403
11438
  if (this.config.docs.readme) {
11404
- const readmePath = path15__default.join(context.projectPath, "README.md");
11405
- await fs14__default.writeFile(readmePath, docs.readme, "utf-8");
11439
+ const readmePath = path16__default.join(context.projectPath, "README.md");
11440
+ await fs15__default.writeFile(readmePath, docs.readme, "utf-8");
11406
11441
  artifacts.push({
11407
11442
  type: "documentation",
11408
11443
  path: readmePath,
@@ -11410,8 +11445,8 @@ var OutputExecutor = class {
11410
11445
  });
11411
11446
  }
11412
11447
  if (this.config.docs.contributing) {
11413
- const contributingPath = path15__default.join(context.projectPath, "CONTRIBUTING.md");
11414
- await fs14__default.writeFile(contributingPath, docs.contributing, "utf-8");
11448
+ const contributingPath = path16__default.join(context.projectPath, "CONTRIBUTING.md");
11449
+ await fs15__default.writeFile(contributingPath, docs.contributing, "utf-8");
11415
11450
  artifacts.push({
11416
11451
  type: "documentation",
11417
11452
  path: contributingPath,
@@ -11419,8 +11454,8 @@ var OutputExecutor = class {
11419
11454
  });
11420
11455
  }
11421
11456
  if (this.config.docs.changelog) {
11422
- const changelogPath = path15__default.join(context.projectPath, "CHANGELOG.md");
11423
- await fs14__default.writeFile(changelogPath, docs.changelog, "utf-8");
11457
+ const changelogPath = path16__default.join(context.projectPath, "CHANGELOG.md");
11458
+ await fs15__default.writeFile(changelogPath, docs.changelog, "utf-8");
11424
11459
  artifacts.push({
11425
11460
  type: "documentation",
11426
11461
  path: changelogPath,
@@ -11428,11 +11463,11 @@ var OutputExecutor = class {
11428
11463
  });
11429
11464
  }
11430
11465
  if (this.config.docs.api) {
11431
- const docsDir = path15__default.join(context.projectPath, "docs");
11466
+ const docsDir = path16__default.join(context.projectPath, "docs");
11432
11467
  await this.ensureDir(docsDir);
11433
11468
  if (docs.api) {
11434
- const apiPath = path15__default.join(docsDir, "api.md");
11435
- await fs14__default.writeFile(apiPath, docs.api, "utf-8");
11469
+ const apiPath = path16__default.join(docsDir, "api.md");
11470
+ await fs15__default.writeFile(apiPath, docs.api, "utf-8");
11436
11471
  artifacts.push({
11437
11472
  type: "documentation",
11438
11473
  path: apiPath,
@@ -11440,8 +11475,8 @@ var OutputExecutor = class {
11440
11475
  });
11441
11476
  }
11442
11477
  if (docs.deployment) {
11443
- const deployPath = path15__default.join(docsDir, "deployment.md");
11444
- await fs14__default.writeFile(deployPath, docs.deployment, "utf-8");
11478
+ const deployPath = path16__default.join(docsDir, "deployment.md");
11479
+ await fs15__default.writeFile(deployPath, docs.deployment, "utf-8");
11445
11480
  artifacts.push({
11446
11481
  type: "documentation",
11447
11482
  path: deployPath,
@@ -11449,8 +11484,8 @@ var OutputExecutor = class {
11449
11484
  });
11450
11485
  }
11451
11486
  if (docs.development) {
11452
- const devPath = path15__default.join(docsDir, "development.md");
11453
- await fs14__default.writeFile(devPath, docs.development, "utf-8");
11487
+ const devPath = path16__default.join(docsDir, "development.md");
11488
+ await fs15__default.writeFile(devPath, docs.development, "utf-8");
11454
11489
  artifacts.push({
11455
11490
  type: "documentation",
11456
11491
  path: devPath,
@@ -11515,16 +11550,16 @@ var OutputExecutor = class {
11515
11550
  */
11516
11551
  async loadMetadata(projectPath) {
11517
11552
  try {
11518
- const packagePath = path15__default.join(projectPath, "package.json");
11519
- const content = await fs14__default.readFile(packagePath, "utf-8");
11553
+ const packagePath = path16__default.join(projectPath, "package.json");
11554
+ const content = await fs15__default.readFile(packagePath, "utf-8");
11520
11555
  const pkg = JSON.parse(content);
11521
11556
  let packageManager = "npm";
11522
11557
  try {
11523
- await fs14__default.access(path15__default.join(projectPath, "pnpm-lock.yaml"));
11558
+ await fs15__default.access(path16__default.join(projectPath, "pnpm-lock.yaml"));
11524
11559
  packageManager = "pnpm";
11525
11560
  } catch {
11526
11561
  try {
11527
- await fs14__default.access(path15__default.join(projectPath, "yarn.lock"));
11562
+ await fs15__default.access(path16__default.join(projectPath, "yarn.lock"));
11528
11563
  packageManager = "yarn";
11529
11564
  } catch {
11530
11565
  }
@@ -11536,7 +11571,7 @@ var OutputExecutor = class {
11536
11571
  repository = pkg.repository.url;
11537
11572
  }
11538
11573
  return {
11539
- name: pkg.name || path15__default.basename(projectPath),
11574
+ name: pkg.name || path16__default.basename(projectPath),
11540
11575
  description: pkg.description || "",
11541
11576
  version: pkg.version || "0.1.0",
11542
11577
  language: "typescript",
@@ -11550,7 +11585,7 @@ var OutputExecutor = class {
11550
11585
  };
11551
11586
  } catch {
11552
11587
  return {
11553
- name: path15__default.basename(projectPath),
11588
+ name: path16__default.basename(projectPath),
11554
11589
  description: "",
11555
11590
  version: "0.1.0",
11556
11591
  language: "typescript",
@@ -11566,7 +11601,7 @@ var OutputExecutor = class {
11566
11601
  * Ensure directory exists
11567
11602
  */
11568
11603
  async ensureDir(dir) {
11569
- await fs14__default.mkdir(dir, { recursive: true });
11604
+ await fs15__default.mkdir(dir, { recursive: true });
11570
11605
  }
11571
11606
  };
11572
11607
  function createOutputExecutor(config) {
@@ -12896,18 +12931,18 @@ async function refreshAccessToken(provider, refreshToken) {
12896
12931
  }
12897
12932
  function getTokenStoragePath(provider) {
12898
12933
  const home = process.env.HOME || process.env.USERPROFILE || "";
12899
- return path15.join(home, ".coco", "tokens", `${provider}.json`);
12934
+ return path16.join(home, ".coco", "tokens", `${provider}.json`);
12900
12935
  }
12901
12936
  async function saveTokens(provider, tokens) {
12902
12937
  const filePath = getTokenStoragePath(provider);
12903
- const dir = path15.dirname(filePath);
12904
- await fs14.mkdir(dir, { recursive: true, mode: 448 });
12905
- await fs14.writeFile(filePath, JSON.stringify(tokens, null, 2), { mode: 384 });
12938
+ const dir = path16.dirname(filePath);
12939
+ await fs15.mkdir(dir, { recursive: true, mode: 448 });
12940
+ await fs15.writeFile(filePath, JSON.stringify(tokens, null, 2), { mode: 384 });
12906
12941
  }
12907
12942
  async function loadTokens(provider) {
12908
12943
  const filePath = getTokenStoragePath(provider);
12909
12944
  try {
12910
- const content = await fs14.readFile(filePath, "utf-8");
12945
+ const content = await fs15.readFile(filePath, "utf-8");
12911
12946
  return JSON.parse(content);
12912
12947
  } catch {
12913
12948
  return null;
@@ -12916,7 +12951,7 @@ async function loadTokens(provider) {
12916
12951
  async function deleteTokens(provider) {
12917
12952
  const filePath = getTokenStoragePath(provider);
12918
12953
  try {
12919
- await fs14.unlink(filePath);
12954
+ await fs15.unlink(filePath);
12920
12955
  } catch {
12921
12956
  }
12922
12957
  }
@@ -13914,9 +13949,9 @@ function createInitialState(config) {
13914
13949
  }
13915
13950
  async function loadExistingState(projectPath) {
13916
13951
  try {
13917
- const fs36 = await import('fs/promises');
13952
+ const fs37 = await import('fs/promises');
13918
13953
  const statePath = `${projectPath}/.coco/state/project.json`;
13919
- const content = await fs36.readFile(statePath, "utf-8");
13954
+ const content = await fs37.readFile(statePath, "utf-8");
13920
13955
  const data = JSON.parse(content);
13921
13956
  data.createdAt = new Date(data.createdAt);
13922
13957
  data.updatedAt = new Date(data.updatedAt);
@@ -13926,13 +13961,13 @@ async function loadExistingState(projectPath) {
13926
13961
  }
13927
13962
  }
13928
13963
  async function saveState(state) {
13929
- const fs36 = await import('fs/promises');
13964
+ const fs37 = await import('fs/promises');
13930
13965
  const statePath = `${state.path}/.coco/state`;
13931
- await fs36.mkdir(statePath, { recursive: true });
13966
+ await fs37.mkdir(statePath, { recursive: true });
13932
13967
  const filePath = `${statePath}/project.json`;
13933
13968
  const tmpPath = `${filePath}.tmp.${Date.now()}`;
13934
- await fs36.writeFile(tmpPath, JSON.stringify(state, null, 2), "utf-8");
13935
- await fs36.rename(tmpPath, filePath);
13969
+ await fs37.writeFile(tmpPath, JSON.stringify(state, null, 2), "utf-8");
13970
+ await fs37.rename(tmpPath, filePath);
13936
13971
  }
13937
13972
  function getPhaseExecutor(phase) {
13938
13973
  switch (phase) {
@@ -13991,20 +14026,20 @@ async function createPhaseContext(config, state) {
13991
14026
  };
13992
14027
  const tools = {
13993
14028
  file: {
13994
- async read(path38) {
13995
- const fs36 = await import('fs/promises');
13996
- return fs36.readFile(path38, "utf-8");
14029
+ async read(path39) {
14030
+ const fs37 = await import('fs/promises');
14031
+ return fs37.readFile(path39, "utf-8");
13997
14032
  },
13998
- async write(path38, content) {
13999
- const fs36 = await import('fs/promises');
14033
+ async write(path39, content) {
14034
+ const fs37 = await import('fs/promises');
14000
14035
  const nodePath = await import('path');
14001
- await fs36.mkdir(nodePath.dirname(path38), { recursive: true });
14002
- await fs36.writeFile(path38, content, "utf-8");
14036
+ await fs37.mkdir(nodePath.dirname(path39), { recursive: true });
14037
+ await fs37.writeFile(path39, content, "utf-8");
14003
14038
  },
14004
- async exists(path38) {
14005
- const fs36 = await import('fs/promises');
14039
+ async exists(path39) {
14040
+ const fs37 = await import('fs/promises');
14006
14041
  try {
14007
- await fs36.access(path38);
14042
+ await fs37.access(path39);
14008
14043
  return true;
14009
14044
  } catch {
14010
14045
  return false;
@@ -14153,9 +14188,9 @@ async function createSnapshot(state) {
14153
14188
  var MAX_CHECKPOINT_VERSIONS = 5;
14154
14189
  async function getCheckpointFiles(state, phase) {
14155
14190
  try {
14156
- const fs36 = await import('fs/promises');
14191
+ const fs37 = await import('fs/promises');
14157
14192
  const checkpointDir = `${state.path}/.coco/checkpoints`;
14158
- const files = await fs36.readdir(checkpointDir);
14193
+ const files = await fs37.readdir(checkpointDir);
14159
14194
  const phaseFiles = files.filter((f) => f.startsWith(`snapshot-pre-${phase}-`) && f.endsWith(".json")).sort((a, b) => {
14160
14195
  const tsA = parseInt(a.split("-").pop()?.replace(".json", "") ?? "0", 10);
14161
14196
  const tsB = parseInt(b.split("-").pop()?.replace(".json", "") ?? "0", 10);
@@ -14168,11 +14203,11 @@ async function getCheckpointFiles(state, phase) {
14168
14203
  }
14169
14204
  async function cleanupOldCheckpoints(state, phase) {
14170
14205
  try {
14171
- const fs36 = await import('fs/promises');
14206
+ const fs37 = await import('fs/promises');
14172
14207
  const files = await getCheckpointFiles(state, phase);
14173
14208
  if (files.length > MAX_CHECKPOINT_VERSIONS) {
14174
14209
  const filesToDelete = files.slice(MAX_CHECKPOINT_VERSIONS);
14175
- await Promise.all(filesToDelete.map((f) => fs36.unlink(f).catch(() => {
14210
+ await Promise.all(filesToDelete.map((f) => fs37.unlink(f).catch(() => {
14176
14211
  })));
14177
14212
  }
14178
14213
  } catch {
@@ -14180,13 +14215,13 @@ async function cleanupOldCheckpoints(state, phase) {
14180
14215
  }
14181
14216
  async function saveSnapshot(state, snapshotId) {
14182
14217
  try {
14183
- const fs36 = await import('fs/promises');
14218
+ const fs37 = await import('fs/promises');
14184
14219
  const snapshotPath = `${state.path}/.coco/checkpoints/snapshot-${snapshotId}.json`;
14185
14220
  const snapshotDir = `${state.path}/.coco/checkpoints`;
14186
- await fs36.mkdir(snapshotDir, { recursive: true });
14221
+ await fs37.mkdir(snapshotDir, { recursive: true });
14187
14222
  const createdAt = state.createdAt instanceof Date ? state.createdAt.toISOString() : String(state.createdAt);
14188
14223
  const updatedAt = state.updatedAt instanceof Date ? state.updatedAt.toISOString() : String(state.updatedAt);
14189
- await fs36.writeFile(
14224
+ await fs37.writeFile(
14190
14225
  snapshotPath,
14191
14226
  JSON.stringify(
14192
14227
  {
@@ -14498,7 +14533,7 @@ async function loadConfig(configPath) {
14498
14533
  async function loadConfigFile(configPath, options = {}) {
14499
14534
  const { strict = true } = options;
14500
14535
  try {
14501
- const content = await fs14__default.readFile(configPath, "utf-8");
14536
+ const content = await fs15__default.readFile(configPath, "utf-8");
14502
14537
  const parsed = JSON5.parse(content);
14503
14538
  if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
14504
14539
  if (!strict) {
@@ -14554,7 +14589,7 @@ function deepMergeConfig(base, override) {
14554
14589
  };
14555
14590
  }
14556
14591
  function getProjectConfigPath2() {
14557
- return path15__default.join(process.cwd(), ".coco", "config.json");
14592
+ return path16__default.join(process.cwd(), ".coco", "config.json");
14558
14593
  }
14559
14594
  async function saveConfig(config, configPath, global = false) {
14560
14595
  const result = CocoConfigSchema.safeParse(config);
@@ -14569,10 +14604,10 @@ async function saveConfig(config, configPath, global = false) {
14569
14604
  });
14570
14605
  }
14571
14606
  const resolvedPath = configPath || (global ? CONFIG_PATHS.config : getProjectConfigPath2());
14572
- const dir = path15__default.dirname(resolvedPath);
14573
- await fs14__default.mkdir(dir, { recursive: true });
14607
+ const dir = path16__default.dirname(resolvedPath);
14608
+ await fs15__default.mkdir(dir, { recursive: true });
14574
14609
  const content = JSON.stringify(result.data, null, 2);
14575
- await fs14__default.writeFile(resolvedPath, content, "utf-8");
14610
+ await fs15__default.writeFile(resolvedPath, content, "utf-8");
14576
14611
  }
14577
14612
  function createDefaultConfig(projectName, language = "typescript") {
14578
14613
  return createDefaultConfigObject(projectName, language);
@@ -14580,7 +14615,7 @@ function createDefaultConfig(projectName, language = "typescript") {
14580
14615
  async function configExists(configPath, scope = "any") {
14581
14616
  if (configPath) {
14582
14617
  try {
14583
- await fs14__default.access(configPath);
14618
+ await fs15__default.access(configPath);
14584
14619
  return true;
14585
14620
  } catch {
14586
14621
  return false;
@@ -14588,7 +14623,7 @@ async function configExists(configPath, scope = "any") {
14588
14623
  }
14589
14624
  if (scope === "project" || scope === "any") {
14590
14625
  try {
14591
- await fs14__default.access(getProjectConfigPath2());
14626
+ await fs15__default.access(getProjectConfigPath2());
14592
14627
  return true;
14593
14628
  } catch {
14594
14629
  if (scope === "project") return false;
@@ -14596,7 +14631,7 @@ async function configExists(configPath, scope = "any") {
14596
14631
  }
14597
14632
  if (scope === "global" || scope === "any") {
14598
14633
  try {
14599
- await fs14__default.access(CONFIG_PATHS.config);
14634
+ await fs15__default.access(CONFIG_PATHS.config);
14600
14635
  return true;
14601
14636
  } catch {
14602
14637
  return false;
@@ -14609,6 +14644,83 @@ z.string().regex(
14609
14644
  "Version must be in semver format (e.g., 1.0.0)"
14610
14645
  );
14611
14646
  init_allowed_paths();
14647
+ function levenshtein(a, b) {
14648
+ if (a === b) return 0;
14649
+ if (a.length === 0) return b.length;
14650
+ if (b.length === 0) return a.length;
14651
+ const row = Array.from({ length: b.length + 1 }, (_, i) => i);
14652
+ for (let i = 1; i <= a.length; i++) {
14653
+ let prev = i;
14654
+ for (let j = 1; j <= b.length; j++) {
14655
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
14656
+ const val = Math.min(
14657
+ row[j] + 1,
14658
+ // deletion
14659
+ prev + 1,
14660
+ // insertion
14661
+ row[j - 1] + cost
14662
+ // substitution
14663
+ );
14664
+ row[j - 1] = prev;
14665
+ prev = val;
14666
+ }
14667
+ row[b.length] = prev;
14668
+ }
14669
+ return row[b.length];
14670
+ }
14671
+
14672
+ // src/utils/file-suggestions.ts
14673
+ var MAX_DIR_ENTRIES = 200;
14674
+ var MAX_SUGGESTIONS = 5;
14675
+ async function suggestSimilarFiles(missingPath, options) {
14676
+ const absPath = path16__default.resolve(missingPath);
14677
+ const dir = path16__default.dirname(absPath);
14678
+ const target = path16__default.basename(absPath);
14679
+ const maxResults = MAX_SUGGESTIONS;
14680
+ try {
14681
+ const entries = await fs15__default.readdir(dir);
14682
+ const limited = entries.slice(0, MAX_DIR_ENTRIES);
14683
+ const scored = limited.map((name) => ({
14684
+ path: path16__default.join(dir, name),
14685
+ distance: levenshtein(target.toLowerCase(), name.toLowerCase())
14686
+ })).filter((s) => s.distance <= Math.max(target.length * 0.6, 3)).sort((a, b) => a.distance - b.distance);
14687
+ return scored.slice(0, maxResults);
14688
+ } catch {
14689
+ return [];
14690
+ }
14691
+ }
14692
+ async function suggestSimilarPaths(missingPath, options) {
14693
+ const fileSuggestions = await suggestSimilarFiles(missingPath);
14694
+ if (fileSuggestions.length > 0) return fileSuggestions;
14695
+ const absPath = path16__default.resolve(missingPath);
14696
+ const grandparent = path16__default.dirname(path16__default.dirname(absPath));
14697
+ const parentBasename = path16__default.basename(path16__default.dirname(absPath));
14698
+ const maxResults = MAX_SUGGESTIONS;
14699
+ try {
14700
+ const entries = await fs15__default.readdir(grandparent, { withFileTypes: true });
14701
+ const dirs = entries.filter((e) => e.isDirectory()).slice(0, MAX_DIR_ENTRIES);
14702
+ const scored = dirs.map((d) => ({
14703
+ path: path16__default.join(grandparent, d.name),
14704
+ distance: levenshtein(parentBasename.toLowerCase(), d.name.toLowerCase())
14705
+ })).filter((s) => s.distance <= Math.max(parentBasename.length * 0.6, 3)).sort((a, b) => a.distance - b.distance);
14706
+ return scored.slice(0, maxResults);
14707
+ } catch {
14708
+ return [];
14709
+ }
14710
+ }
14711
+ function formatSuggestions(suggestions, baseDir) {
14712
+ if (suggestions.length === 0) return "";
14713
+ const base = baseDir ?? process.cwd();
14714
+ const lines = suggestions.map((s) => {
14715
+ const rel = path16__default.relative(base, s.path);
14716
+ return ` - ${rel}`;
14717
+ });
14718
+ return `
14719
+ Did you mean?
14720
+ ${lines.join("\n")}`;
14721
+ }
14722
+
14723
+ // src/tools/file.ts
14612
14724
  var SENSITIVE_PATTERNS = [
14613
14725
  /\.env(?:\.\w+)?$/,
14614
14726
  // .env, .env.local, etc.
@@ -14633,7 +14745,7 @@ function hasNullByte(str) {
14633
14745
  }
14634
14746
  function normalizePath(filePath) {
14635
14747
  let normalized = filePath.replace(/\0/g, "");
14636
- normalized = path15__default.normalize(normalized);
14748
+ normalized = path16__default.normalize(normalized);
14637
14749
  return normalized;
14638
14750
  }
14639
14751
  function isPathAllowed(filePath, operation) {
@@ -14641,31 +14753,31 @@ function isPathAllowed(filePath, operation) {
14641
14753
  return { allowed: false, reason: "Path contains invalid characters" };
14642
14754
  }
14643
14755
  const normalized = normalizePath(filePath);
14644
- const absolute = path15__default.resolve(normalized);
14756
+ const absolute = path16__default.resolve(normalized);
14645
14757
  const cwd = process.cwd();
14646
14758
  for (const blocked of BLOCKED_PATHS) {
14647
- const normalizedBlocked = path15__default.normalize(blocked);
14648
- if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked + path15__default.sep)) {
14759
+ const normalizedBlocked = path16__default.normalize(blocked);
14760
+ if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked + path16__default.sep)) {
14649
14761
  return { allowed: false, reason: `Access to system path '${blocked}' is not allowed` };
14650
14762
  }
14651
14763
  }
14652
14764
  const home = process.env.HOME;
14653
14765
  if (home) {
14654
- const normalizedHome = path15__default.normalize(home);
14655
- const normalizedCwd = path15__default.normalize(cwd);
14766
+ const normalizedHome = path16__default.normalize(home);
14767
+ const normalizedCwd = path16__default.normalize(cwd);
14656
14768
  if (absolute.startsWith(normalizedHome) && !absolute.startsWith(normalizedCwd)) {
14657
14769
  if (isWithinAllowedPath(absolute, operation)) ; else if (operation === "read") {
14658
14770
  const allowedHomeReads = [".gitconfig", ".zshrc", ".bashrc"];
14659
- const basename5 = path15__default.basename(absolute);
14771
+ const basename5 = path16__default.basename(absolute);
14660
14772
  if (!allowedHomeReads.includes(basename5)) {
14661
- const targetDir = path15__default.dirname(absolute);
14773
+ const targetDir = path16__default.dirname(absolute);
14662
14774
  return {
14663
14775
  allowed: false,
14664
14776
  reason: `Reading files outside project directory is not allowed. Use /allow-path ${targetDir} to grant access.`
14665
14777
  };
14666
14778
  }
14667
14779
  } else {
14668
- const targetDir = path15__default.dirname(absolute);
14780
+ const targetDir = path16__default.dirname(absolute);
14669
14781
  return {
14670
14782
  allowed: false,
14671
14783
  reason: `${operation} operations outside project directory are not allowed. Use /allow-path ${targetDir} to grant access.`
@@ -14674,7 +14786,7 @@ function isPathAllowed(filePath, operation) {
14674
14786
  }
14675
14787
  }
14676
14788
  if (operation === "write" || operation === "delete") {
14677
- const basename5 = path15__default.basename(absolute);
14789
+ const basename5 = path16__default.basename(absolute);
14678
14790
  for (const pattern of SENSITIVE_PATTERNS) {
14679
14791
  if (pattern.test(basename5)) {
14680
14792
  return {
@@ -14693,6 +14805,24 @@ function validatePath(filePath, operation) {
14693
14805
  }
14694
14806
  }
14695
14807
  var DEFAULT_MAX_FILE_SIZE = 10 * 1024 * 1024;
14808
+ function isENOENT(error) {
14809
+ return error.code === "ENOENT";
14810
+ }
14811
+ async function enrichENOENT(filePath, operation) {
14812
+ const absPath = path16__default.resolve(filePath);
14813
+ const suggestions = await suggestSimilarFiles(absPath);
14814
+ const hint = formatSuggestions(suggestions, path16__default.dirname(absPath));
14815
+ const action = operation === "read" ? "Use glob or list_dir to find the correct path." : "Check that the parent directory exists.";
14816
+ return `File not found: ${filePath}${hint}
14817
+ ${action}`;
14818
+ }
14819
+ async function enrichDirENOENT(dirPath) {
14820
+ const absPath = path16__default.resolve(dirPath);
14821
+ const suggestions = await suggestSimilarPaths(absPath);
14822
+ const hint = formatSuggestions(suggestions, path16__default.dirname(absPath));
14823
+ return `Directory not found: ${dirPath}${hint}
14824
+ Use list_dir or glob to find the correct path.`;
14825
+ }
14696
14826
  var readFileTool = defineTool({
14697
14827
  name: "read_file",
14698
14828
  description: `Read the contents of a file.
@@ -14710,13 +14840,13 @@ Examples:
14710
14840
  async execute({ path: filePath, encoding, maxSize }) {
14711
14841
  validatePath(filePath, "read");
14712
14842
  try {
14713
- const absolutePath = path15__default.resolve(filePath);
14714
- const stats = await fs14__default.stat(absolutePath);
14843
+ const absolutePath = path16__default.resolve(filePath);
14844
+ const stats = await fs15__default.stat(absolutePath);
14715
14845
  const maxBytes = maxSize ?? DEFAULT_MAX_FILE_SIZE;
14716
14846
  let truncated = false;
14717
14847
  let content;
14718
14848
  if (stats.size > maxBytes) {
14719
- const handle = await fs14__default.open(absolutePath, "r");
14849
+ const handle = await fs15__default.open(absolutePath, "r");
14720
14850
  try {
14721
14851
  const buffer = Buffer.alloc(maxBytes);
14722
14852
  await handle.read(buffer, 0, maxBytes, 0);
@@ -14726,7 +14856,7 @@ Examples:
14726
14856
  await handle.close();
14727
14857
  }
14728
14858
  } else {
14729
- content = await fs14__default.readFile(absolutePath, encoding);
14859
+ content = await fs15__default.readFile(absolutePath, encoding);
14730
14860
  }
14731
14861
  return {
14732
14862
  content,
@@ -14735,6 +14865,14 @@ Examples:
14735
14865
  truncated
14736
14866
  };
14737
14867
  } catch (error) {
14868
+ if (isENOENT(error)) {
14869
+ const enriched = await enrichENOENT(filePath, "read");
14870
+ throw new FileSystemError(enriched, {
14871
+ path: filePath,
14872
+ operation: "read",
14873
+ cause: error instanceof Error ? error : void 0
14874
+ });
14875
+ }
14738
14876
  throw new FileSystemError(`Failed to read file: ${filePath}`, {
14739
14877
  path: filePath,
14740
14878
  operation: "read",
@@ -14761,10 +14899,10 @@ Examples:
14761
14899
  async execute({ path: filePath, content, createDirs, dryRun }) {
14762
14900
  validatePath(filePath, "write");
14763
14901
  try {
14764
- const absolutePath = path15__default.resolve(filePath);
14902
+ const absolutePath = path16__default.resolve(filePath);
14765
14903
  let wouldCreate = false;
14766
14904
  try {
14767
- await fs14__default.access(absolutePath);
14905
+ await fs15__default.access(absolutePath);
14768
14906
  } catch {
14769
14907
  wouldCreate = true;
14770
14908
  }
@@ -14777,10 +14915,10 @@ Examples:
14777
14915
  };
14778
14916
  }
14779
14917
  if (createDirs) {
14780
- await fs14__default.mkdir(path15__default.dirname(absolutePath), { recursive: true });
14918
+ await fs15__default.mkdir(path16__default.dirname(absolutePath), { recursive: true });
14781
14919
  }
14782
- await fs14__default.writeFile(absolutePath, content, "utf-8");
14783
- const stats = await fs14__default.stat(absolutePath);
14920
+ await fs15__default.writeFile(absolutePath, content, "utf-8");
14921
+ const stats = await fs15__default.stat(absolutePath);
14784
14922
  return {
14785
14923
  path: absolutePath,
14786
14924
  size: stats.size,
@@ -14788,6 +14926,14 @@ Examples:
14788
14926
  wouldCreate
14789
14927
  };
14790
14928
  } catch (error) {
14929
+ if (isENOENT(error)) {
14930
+ const enriched = await enrichENOENT(filePath, "write");
14931
+ throw new FileSystemError(enriched, {
14932
+ path: filePath,
14933
+ operation: "write",
14934
+ cause: error instanceof Error ? error : void 0
14935
+ });
14936
+ }
14791
14937
  throw new FileSystemError(`Failed to write file: ${filePath}`, {
14792
14938
  path: filePath,
14793
14939
  operation: "write",
@@ -14815,8 +14961,8 @@ Examples:
14815
14961
  async execute({ path: filePath, oldText, newText, all, dryRun }) {
14816
14962
  validatePath(filePath, "write");
14817
14963
  try {
14818
- const absolutePath = path15__default.resolve(filePath);
14819
- let content = await fs14__default.readFile(absolutePath, "utf-8");
14964
+ const absolutePath = path16__default.resolve(filePath);
14965
+ let content = await fs15__default.readFile(absolutePath, "utf-8");
14820
14966
  let replacements = 0;
14821
14967
  if (all) {
14822
14968
  const regex = new RegExp(escapeRegex(oldText), "g");
@@ -14830,7 +14976,31 @@ Examples:
14830
14976
  }
14831
14977
  }
14832
14978
  if (replacements === 0) {
14833
- throw new Error(`Text not found in file: "${oldText.slice(0, 50)}..."`);
14979
+ const lines = content.split("\n");
14980
+ const searchLine = (oldText.split("\n")[0] ?? oldText).trim().slice(0, 80);
14981
+ let bestIdx = -1;
14982
+ let bestDist = Infinity;
14983
+ for (let i = 0; i < lines.length; i++) {
14984
+ const dist = levenshtein(lines[i].trim().slice(0, 80), searchLine);
14985
+ if (dist < bestDist) {
14986
+ bestDist = dist;
14987
+ bestIdx = i;
14988
+ }
14989
+ }
14990
+ let context = "";
14991
+ if (bestIdx >= 0 && bestDist < searchLine.length * 0.6) {
14992
+ const start = Math.max(0, bestIdx - 2);
14993
+ const end = Math.min(lines.length, bestIdx + 3);
14994
+ const snippet = lines.slice(start, end).map((l, i) => ` ${start + i + 1}: ${l}`).join("\n");
14995
+ context = `
14996
+
14997
+ Closest match near line ${bestIdx + 1}:
14998
+ ${snippet}`;
14999
+ }
15000
+ throw new Error(
15001
+ `Text not found in file: "${oldText.slice(0, 50)}..."${context}
15002
+ Hint: Use read_file first to verify the exact content.`
15003
+ );
14834
15004
  }
14835
15005
  if (dryRun) {
14836
15006
  const preview = content.length > 500 ? content.slice(0, 500) + "..." : content;
@@ -14841,7 +15011,7 @@ Examples:
14841
15011
  preview
14842
15012
  };
14843
15013
  }
14844
- await fs14__default.writeFile(absolutePath, content, "utf-8");
15014
+ await fs15__default.writeFile(absolutePath, content, "utf-8");
14845
15015
  return {
14846
15016
  path: absolutePath,
14847
15017
  replacements,
@@ -14882,6 +15052,14 @@ Examples:
14882
15052
  count: files.length
14883
15053
  };
14884
15054
  } catch (error) {
15055
+ if (isENOENT(error) && cwd) {
15056
+ const enriched = await enrichDirENOENT(cwd);
15057
+ throw new FileSystemError(`Glob search failed \u2014 ${enriched}`, {
15058
+ path: cwd,
15059
+ operation: "glob",
15060
+ cause: error instanceof Error ? error : void 0
15061
+ });
15062
+ }
14885
15063
  throw new FileSystemError(`Glob search failed: ${pattern}`, {
14886
15064
  path: cwd ?? process.cwd(),
14887
15065
  operation: "glob",
@@ -14904,8 +15082,8 @@ Examples:
14904
15082
  }),
14905
15083
  async execute({ path: filePath }) {
14906
15084
  try {
14907
- const absolutePath = path15__default.resolve(filePath);
14908
- const stats = await fs14__default.stat(absolutePath);
15085
+ const absolutePath = path16__default.resolve(filePath);
15086
+ const stats = await fs15__default.stat(absolutePath);
14909
15087
  return {
14910
15088
  exists: true,
14911
15089
  isFile: stats.isFile(),
@@ -14935,12 +15113,12 @@ Examples:
14935
15113
  }),
14936
15114
  async execute({ path: dirPath, recursive }) {
14937
15115
  try {
14938
- const absolutePath = path15__default.resolve(dirPath);
15116
+ const absolutePath = path16__default.resolve(dirPath);
14939
15117
  const entries = [];
14940
15118
  async function listDir(dir, prefix = "") {
14941
- const items = await fs14__default.readdir(dir, { withFileTypes: true });
15119
+ const items = await fs15__default.readdir(dir, { withFileTypes: true });
14942
15120
  for (const item of items) {
14943
- const fullPath = path15__default.join(dir, item.name);
15121
+ const fullPath = path16__default.join(dir, item.name);
14944
15122
  const relativePath = prefix ? `${prefix}/${item.name}` : item.name;
14945
15123
  if (item.isDirectory()) {
14946
15124
  entries.push({ name: relativePath, type: "directory" });
@@ -14948,7 +15126,7 @@ Examples:
14948
15126
  await listDir(fullPath, relativePath);
14949
15127
  }
14950
15128
  } else if (item.isFile()) {
14951
- const stats = await fs14__default.stat(fullPath);
15129
+ const stats = await fs15__default.stat(fullPath);
14952
15130
  entries.push({ name: relativePath, type: "file", size: stats.size });
14953
15131
  }
14954
15132
  }
@@ -14956,6 +15134,14 @@ Examples:
14956
15134
  await listDir(absolutePath);
14957
15135
  return { entries };
14958
15136
  } catch (error) {
15137
+ if (isENOENT(error)) {
15138
+ const enriched = await enrichDirENOENT(dirPath);
15139
+ throw new FileSystemError(enriched, {
15140
+ path: dirPath,
15141
+ operation: "read",
15142
+ cause: error instanceof Error ? error : void 0
15143
+ });
15144
+ }
14959
15145
  throw new FileSystemError(`Failed to list directory: ${dirPath}`, {
14960
15146
  path: dirPath,
14961
15147
  operation: "read",
@@ -14987,23 +15173,23 @@ Examples:
14987
15173
  }
14988
15174
  validatePath(filePath, "delete");
14989
15175
  try {
14990
- const absolutePath = path15__default.resolve(filePath);
14991
- const stats = await fs14__default.stat(absolutePath);
15176
+ const absolutePath = path16__default.resolve(filePath);
15177
+ const stats = await fs15__default.stat(absolutePath);
14992
15178
  if (stats.isDirectory()) {
14993
15179
  if (!recursive) {
14994
15180
  throw new ToolError("Cannot delete directory without recursive: true", {
14995
15181
  tool: "delete_file"
14996
15182
  });
14997
15183
  }
14998
- await fs14__default.rm(absolutePath, { recursive: true });
15184
+ await fs15__default.rm(absolutePath, { recursive: true });
14999
15185
  } else {
15000
- await fs14__default.unlink(absolutePath);
15186
+ await fs15__default.unlink(absolutePath);
15001
15187
  }
15002
15188
  return { deleted: true, path: absolutePath };
15003
15189
  } catch (error) {
15004
15190
  if (error instanceof ToolError) throw error;
15005
15191
  if (error.code === "ENOENT") {
15006
- return { deleted: false, path: path15__default.resolve(filePath) };
15192
+ return { deleted: false, path: path16__default.resolve(filePath) };
15007
15193
  }
15008
15194
  throw new FileSystemError(`Failed to delete: ${filePath}`, {
15009
15195
  path: filePath,
@@ -15031,11 +15217,11 @@ Examples:
15031
15217
  validatePath(source, "read");
15032
15218
  validatePath(destination, "write");
15033
15219
  try {
15034
- const srcPath = path15__default.resolve(source);
15035
- const destPath = path15__default.resolve(destination);
15220
+ const srcPath = path16__default.resolve(source);
15221
+ const destPath = path16__default.resolve(destination);
15036
15222
  if (!overwrite) {
15037
15223
  try {
15038
- await fs14__default.access(destPath);
15224
+ await fs15__default.access(destPath);
15039
15225
  throw new ToolError(
15040
15226
  `Destination already exists: ${destination}. Use overwrite: true to replace.`,
15041
15227
  {
@@ -15048,9 +15234,9 @@ Examples:
15048
15234
  }
15049
15235
  }
15050
15236
  }
15051
- await fs14__default.mkdir(path15__default.dirname(destPath), { recursive: true });
15052
- await fs14__default.copyFile(srcPath, destPath);
15053
- const stats = await fs14__default.stat(destPath);
15237
+ await fs15__default.mkdir(path16__default.dirname(destPath), { recursive: true });
15238
+ await fs15__default.copyFile(srcPath, destPath);
15239
+ const stats = await fs15__default.stat(destPath);
15054
15240
  return {
15055
15241
  source: srcPath,
15056
15242
  destination: destPath,
@@ -15058,6 +15244,14 @@ Examples:
15058
15244
  };
15059
15245
  } catch (error) {
15060
15246
  if (error instanceof ToolError) throw error;
15247
+ if (isENOENT(error)) {
15248
+ const enriched = await enrichENOENT(source, "read");
15249
+ throw new FileSystemError(`Failed to copy \u2014 ${enriched}`, {
15250
+ path: source,
15251
+ operation: "read",
15252
+ cause: error instanceof Error ? error : void 0
15253
+ });
15254
+ }
15061
15255
  throw new FileSystemError(`Failed to copy file: ${source} -> ${destination}`, {
15062
15256
  path: source,
15063
15257
  operation: "read",
@@ -15084,11 +15278,11 @@ Examples:
15084
15278
  validatePath(source, "delete");
15085
15279
  validatePath(destination, "write");
15086
15280
  try {
15087
- const srcPath = path15__default.resolve(source);
15088
- const destPath = path15__default.resolve(destination);
15281
+ const srcPath = path16__default.resolve(source);
15282
+ const destPath = path16__default.resolve(destination);
15089
15283
  if (!overwrite) {
15090
15284
  try {
15091
- await fs14__default.access(destPath);
15285
+ await fs15__default.access(destPath);
15092
15286
  throw new ToolError(
15093
15287
  `Destination already exists: ${destination}. Use overwrite: true to replace.`,
15094
15288
  {
@@ -15101,14 +15295,22 @@ Examples:
15101
15295
  }
15102
15296
  }
15103
15297
  }
15104
- await fs14__default.mkdir(path15__default.dirname(destPath), { recursive: true });
15105
- await fs14__default.rename(srcPath, destPath);
15298
+ await fs15__default.mkdir(path16__default.dirname(destPath), { recursive: true });
15299
+ await fs15__default.rename(srcPath, destPath);
15106
15300
  return {
15107
15301
  source: srcPath,
15108
15302
  destination: destPath
15109
15303
  };
15110
15304
  } catch (error) {
15111
15305
  if (error instanceof ToolError) throw error;
15306
+ if (isENOENT(error)) {
15307
+ const enriched = await enrichENOENT(source, "read");
15308
+ throw new FileSystemError(`Failed to move \u2014 ${enriched}`, {
15309
+ path: source,
15310
+ operation: "write",
15311
+ cause: error instanceof Error ? error : void 0
15312
+ });
15313
+ }
15112
15314
  throw new FileSystemError(`Failed to move file: ${source} -> ${destination}`, {
15113
15315
  path: source,
15114
15316
  operation: "write",
@@ -15136,13 +15338,13 @@ Examples:
15136
15338
  }),
15137
15339
  async execute({ path: dirPath, depth, showHidden, dirsOnly }) {
15138
15340
  try {
15139
- const absolutePath = path15__default.resolve(dirPath ?? ".");
15341
+ const absolutePath = path16__default.resolve(dirPath ?? ".");
15140
15342
  let totalFiles = 0;
15141
15343
  let totalDirs = 0;
15142
- const lines = [path15__default.basename(absolutePath) + "/"];
15344
+ const lines = [path16__default.basename(absolutePath) + "/"];
15143
15345
  async function buildTree(dir, prefix, currentDepth) {
15144
15346
  if (currentDepth > (depth ?? 4)) return;
15145
- let items = await fs14__default.readdir(dir, { withFileTypes: true });
15347
+ let items = await fs15__default.readdir(dir, { withFileTypes: true });
15146
15348
  if (!showHidden) {
15147
15349
  items = items.filter((item) => !item.name.startsWith("."));
15148
15350
  }
@@ -15162,7 +15364,7 @@ Examples:
15162
15364
  if (item.isDirectory()) {
15163
15365
  totalDirs++;
15164
15366
  lines.push(`${prefix}${connector}${item.name}/`);
15165
- await buildTree(path15__default.join(dir, item.name), prefix + childPrefix, currentDepth + 1);
15367
+ await buildTree(path16__default.join(dir, item.name), prefix + childPrefix, currentDepth + 1);
15166
15368
  } else {
15167
15369
  totalFiles++;
15168
15370
  lines.push(`${prefix}${connector}${item.name}`);
@@ -15176,6 +15378,14 @@ Examples:
15176
15378
  totalDirs
15177
15379
  };
15178
15380
  } catch (error) {
15381
+ if (isENOENT(error)) {
15382
+ const enriched = await enrichDirENOENT(dirPath ?? ".");
15383
+ throw new FileSystemError(enriched, {
15384
+ path: dirPath ?? ".",
15385
+ operation: "read",
15386
+ cause: error instanceof Error ? error : void 0
15387
+ });
15388
+ }
15179
15389
  throw new FileSystemError(`Failed to generate tree: ${dirPath}`, {
15180
15390
  path: dirPath ?? ".",
15181
15391
  operation: "read",
@@ -15202,40 +15412,24 @@ function escapeRegex(str) {
15202
15412
  var DEFAULT_TIMEOUT_MS = 12e4;
15203
15413
  var MAX_OUTPUT_SIZE = 1024 * 1024;
15204
15414
  var DANGEROUS_PATTERNS_FULL = [
15205
- /\brm\s+-rf\s+\/(?!\w)/,
15206
- // rm -rf / (root)
15207
- /\bsudo\s+rm\s+-rf/,
15208
- // sudo rm -rf
15209
- /\b:?\(\)\s*\{.*\}/,
15210
- // Fork bomb pattern
15211
- /\bdd\s+if=.*of=\/dev\//,
15212
- // dd to device
15213
- /\bmkfs\./,
15214
- // Format filesystem
15215
- /\bformat\s+/,
15216
- // Windows format
15217
- />\s*\/etc\//,
15218
- // Write to /etc
15219
- />\s*\/root\//,
15220
- // Write to /root
15221
- /\bchmod\s+777/,
15222
- // Overly permissive chmod
15223
- /\bchown\s+root/,
15224
- // chown to root
15225
- /\bcurl\s+.*\|\s*(ba)?sh/,
15226
- // curl | sh pattern
15227
- /\bwget\s+.*\|\s*(ba)?sh/
15228
- // wget | sh pattern
15415
+ { pattern: /\brm\s+-rf\s+\/(?!\w)/, rule: "rm -rf on root filesystem" },
15416
+ { pattern: /\bsudo\s+rm\s+-rf/, rule: "sudo rm -rf (destructive with elevated privileges)" },
15417
+ { pattern: /\b:?\(\)\s*\{.*\}/, rule: "fork bomb pattern" },
15418
+ { pattern: /\bdd\s+if=.*of=\/dev\//, rule: "dd write to device" },
15419
+ { pattern: /\bmkfs\./, rule: "filesystem format command" },
15420
+ { pattern: /\bformat\s+/, rule: "format command" },
15421
+ { pattern: />\s*\/etc\//, rule: "write redirect to /etc/" },
15422
+ { pattern: />\s*\/root\//, rule: "write redirect to /root/" },
15423
+ { pattern: /\bchmod\s+777/, rule: "overly permissive chmod 777" },
15424
+ { pattern: /\bchown\s+root/, rule: "chown to root" },
15425
+ { pattern: /\bcurl\s+.*\|\s*(ba)?sh/, rule: "curl pipe to shell (untrusted code execution)" },
15426
+ { pattern: /\bwget\s+.*\|\s*(ba)?sh/, rule: "wget pipe to shell (untrusted code execution)" }
15229
15427
  ];
15230
15428
  var DANGEROUS_PATTERNS_SHELL_ONLY = [
15231
- /`[^`]+`/,
15232
- // Backtick command substitution
15233
- /\$\([^)]+\)/,
15234
- // $() command substitution
15235
- /\beval\s+/,
15236
- // eval command (shell eval, not JS eval())
15237
- /\bsource\s+/
15238
- // source command (can execute arbitrary scripts)
15429
+ { pattern: /`[^`]+`/, rule: "backtick command substitution" },
15430
+ { pattern: /\$\([^)]+\)/, rule: "$() command substitution" },
15431
+ { pattern: /\beval\s+/, rule: "eval command (arbitrary code execution)" },
15432
+ { pattern: /\bsource\s+/, rule: "source command (can execute arbitrary scripts)" }
15239
15433
  ];
15240
15434
  function getShellCommandPart(command) {
15241
15435
  const firstNewline = command.indexOf("\n");
@@ -15313,18 +15507,20 @@ Examples:
15313
15507
  }),
15314
15508
  async execute({ command, cwd, timeout, env: env2 }) {
15315
15509
  const shellPart = getShellCommandPart(command);
15316
- for (const pattern of DANGEROUS_PATTERNS_FULL) {
15510
+ for (const { pattern, rule } of DANGEROUS_PATTERNS_FULL) {
15317
15511
  if (pattern.test(command)) {
15318
- throw new ToolError(`Potentially dangerous command blocked: ${command.slice(0, 100)}`, {
15319
- tool: "bash_exec"
15320
- });
15512
+ throw new ToolError(
15513
+ `Command blocked by safety rule: "${rule}". Rewrite the command to avoid this pattern, or use a safer alternative.`,
15514
+ { tool: "bash_exec" }
15515
+ );
15321
15516
  }
15322
15517
  }
15323
- for (const pattern of DANGEROUS_PATTERNS_SHELL_ONLY) {
15518
+ for (const { pattern, rule } of DANGEROUS_PATTERNS_SHELL_ONLY) {
15324
15519
  if (pattern.test(shellPart)) {
15325
- throw new ToolError(`Potentially dangerous command blocked: ${command.slice(0, 100)}`, {
15326
- tool: "bash_exec"
15327
- });
15520
+ throw new ToolError(
15521
+ `Command blocked by safety rule: "${rule}". Rewrite the command to avoid this pattern, or use a safer alternative.`,
15522
+ { tool: "bash_exec" }
15523
+ );
15328
15524
  }
15329
15525
  }
15330
15526
  const startTime = performance.now();
@@ -15409,18 +15605,20 @@ Examples:
15409
15605
  }),
15410
15606
  async execute({ command, cwd, env: env2 }) {
15411
15607
  const shellPart = getShellCommandPart(command);
15412
- for (const pattern of DANGEROUS_PATTERNS_FULL) {
15608
+ for (const { pattern, rule } of DANGEROUS_PATTERNS_FULL) {
15413
15609
  if (pattern.test(command)) {
15414
- throw new ToolError(`Potentially dangerous command blocked: ${command.slice(0, 100)}`, {
15415
- tool: "bash_background"
15416
- });
15610
+ throw new ToolError(
15611
+ `Command blocked by safety rule: "${rule}". Rewrite the command to avoid this pattern, or use a safer alternative.`,
15612
+ { tool: "bash_background" }
15613
+ );
15417
15614
  }
15418
15615
  }
15419
- for (const pattern of DANGEROUS_PATTERNS_SHELL_ONLY) {
15616
+ for (const { pattern, rule } of DANGEROUS_PATTERNS_SHELL_ONLY) {
15420
15617
  if (pattern.test(shellPart)) {
15421
- throw new ToolError(`Potentially dangerous command blocked: ${command.slice(0, 100)}`, {
15422
- tool: "bash_background"
15423
- });
15618
+ throw new ToolError(
15619
+ `Command blocked by safety rule: "${rule}". Rewrite the command to avoid this pattern, or use a safer alternative.`,
15620
+ { tool: "bash_background" }
15621
+ );
15424
15622
  }
15425
15623
  }
15426
15624
  try {
@@ -15528,6 +15726,27 @@ function truncateOutput(output, maxLength = 5e4) {
15528
15726
 
15529
15727
  [Output truncated - ${output.length - maxLength} more characters]`;
15530
15728
  }
15729
+ function enrichGitError(operation, error) {
15730
+ const msg = error instanceof Error ? error.message : String(error);
15731
+ if (/not a git repository/i.test(msg))
15732
+ return `Not a git repository. Run git_init first or verify you're in the correct directory.`;
15733
+ if (/nothing to commit/i.test(msg))
15734
+ return `Nothing to commit \u2014 working tree is clean. Use git_status to verify your changes were saved.`;
15735
+ if (/CONFLICT|merge conflict/i.test(msg))
15736
+ return `Merge conflict detected. Use read_file to see the conflicting file, resolve manually with edit_file, then git_add and git_commit.`;
15737
+ if (/non-fast-forward|\[rejected\]/i.test(msg))
15738
+ return `Push rejected \u2014 remote has new commits. Run git_pull first, resolve any conflicts, then retry git_push.`;
15739
+ if (/authentication failed/i.test(msg))
15740
+ return `Git authentication failed. Check your credentials, SSH key, or access token.`;
15741
+ if (/branch.*already exists/i.test(msg))
15742
+ return `Branch already exists. Use git_checkout to switch to it, or choose a different name.`;
15743
+ if (/does not exist|unknown revision|bad revision/i.test(msg))
15744
+ return `Git reference not found. Use git_branch to list available branches, or git_log to find the correct commit.`;
15745
+ if (/pathspec.*did not match/i.test(msg))
15746
+ return `File not tracked by git. Use glob to verify the file exists, then git_add it first.`;
15747
+ if (/already up to date/i.test(msg)) return `Already up to date \u2014 no changes to pull.`;
15748
+ return `Git ${operation} failed: ${msg}`;
15749
+ }
15531
15750
  function getGit(cwd) {
15532
15751
  const baseDir = cwd ?? process.cwd();
15533
15752
  return simpleGit({ baseDir });
@@ -15559,10 +15778,10 @@ Examples:
15559
15778
  isClean: status.isClean()
15560
15779
  };
15561
15780
  } catch (error) {
15562
- throw new ToolError(
15563
- `Git status failed: ${error instanceof Error ? error.message : String(error)}`,
15564
- { tool: "git_status", cause: error instanceof Error ? error : void 0 }
15565
- );
15781
+ throw new ToolError(enrichGitError("status", error), {
15782
+ tool: "git_status",
15783
+ cause: error instanceof Error ? error : void 0
15784
+ });
15566
15785
  }
15567
15786
  }
15568
15787
  });
@@ -15596,10 +15815,10 @@ Examples:
15596
15815
  deletions: diffStat.deletions
15597
15816
  };
15598
15817
  } catch (error) {
15599
- throw new ToolError(
15600
- `Git diff failed: ${error instanceof Error ? error.message : String(error)}`,
15601
- { tool: "git_diff", cause: error instanceof Error ? error : void 0 }
15602
- );
15818
+ throw new ToolError(enrichGitError("diff", error), {
15819
+ tool: "git_diff",
15820
+ cause: error instanceof Error ? error : void 0
15821
+ });
15603
15822
  }
15604
15823
  }
15605
15824
  });
@@ -15622,10 +15841,10 @@ Examples:
15622
15841
  await git.add(files);
15623
15842
  return { added: files };
15624
15843
  } catch (error) {
15625
- throw new ToolError(
15626
- `Git add failed: ${error instanceof Error ? error.message : String(error)}`,
15627
- { tool: "git_add", cause: error instanceof Error ? error : void 0 }
15628
- );
15844
+ throw new ToolError(enrichGitError("add", error), {
15845
+ tool: "git_add",
15846
+ cause: error instanceof Error ? error : void 0
15847
+ });
15629
15848
  }
15630
15849
  }
15631
15850
  });
@@ -15655,10 +15874,10 @@ Examples:
15655
15874
  summary: result.summary.changes ? `${result.summary.insertions} insertions, ${result.summary.deletions} deletions` : "No changes"
15656
15875
  };
15657
15876
  } catch (error) {
15658
- throw new ToolError(
15659
- `Git commit failed: ${error instanceof Error ? error.message : String(error)}`,
15660
- { tool: "git_commit", cause: error instanceof Error ? error : void 0 }
15661
- );
15877
+ throw new ToolError(enrichGitError("commit", error), {
15878
+ tool: "git_commit",
15879
+ cause: error instanceof Error ? error : void 0
15880
+ });
15662
15881
  }
15663
15882
  }
15664
15883
  });
@@ -15695,10 +15914,10 @@ Examples:
15695
15914
  }))
15696
15915
  };
15697
15916
  } catch (error) {
15698
- throw new ToolError(
15699
- `Git log failed: ${error instanceof Error ? error.message : String(error)}`,
15700
- { tool: "git_log", cause: error instanceof Error ? error : void 0 }
15701
- );
15917
+ throw new ToolError(enrichGitError("log", error), {
15918
+ tool: "git_log",
15919
+ cause: error instanceof Error ? error : void 0
15920
+ });
15702
15921
  }
15703
15922
  }
15704
15923
  });
@@ -15739,10 +15958,10 @@ Examples:
15739
15958
  current: status.current ?? "HEAD"
15740
15959
  };
15741
15960
  } catch (error) {
15742
- throw new ToolError(
15743
- `Git branch failed: ${error instanceof Error ? error.message : String(error)}`,
15744
- { tool: "git_branch", cause: error instanceof Error ? error : void 0 }
15745
- );
15961
+ throw new ToolError(enrichGitError("branch", error), {
15962
+ tool: "git_branch",
15963
+ cause: error instanceof Error ? error : void 0
15964
+ });
15746
15965
  }
15747
15966
  }
15748
15967
  });
@@ -15769,10 +15988,10 @@ Examples:
15769
15988
  }
15770
15989
  return { branch };
15771
15990
  } catch (error) {
15772
- throw new ToolError(
15773
- `Git checkout failed: ${error instanceof Error ? error.message : String(error)}`,
15774
- { tool: "git_checkout", cause: error instanceof Error ? error : void 0 }
15775
- );
15991
+ throw new ToolError(enrichGitError("checkout", error), {
15992
+ tool: "git_checkout",
15993
+ cause: error instanceof Error ? error : void 0
15994
+ });
15776
15995
  }
15777
15996
  }
15778
15997
  });
@@ -15807,10 +16026,10 @@ Examples:
15807
16026
  branch: pushBranch
15808
16027
  };
15809
16028
  } catch (error) {
15810
- throw new ToolError(
15811
- `Git push failed: ${error instanceof Error ? error.message : String(error)}`,
15812
- { tool: "git_push", cause: error instanceof Error ? error : void 0 }
15813
- );
16029
+ throw new ToolError(enrichGitError("push", error), {
16030
+ tool: "git_push",
16031
+ cause: error instanceof Error ? error : void 0
16032
+ });
15814
16033
  }
15815
16034
  }
15816
16035
  });
@@ -15842,10 +16061,10 @@ Examples:
15842
16061
  summary: result.summary ? `${result.summary.insertions} insertions, ${result.summary.deletions} deletions` : "Already up to date"
15843
16062
  };
15844
16063
  } catch (error) {
15845
- throw new ToolError(
15846
- `Git pull failed: ${error instanceof Error ? error.message : String(error)}`,
15847
- { tool: "git_pull", cause: error instanceof Error ? error : void 0 }
15848
- );
16064
+ throw new ToolError(enrichGitError("pull", error), {
16065
+ tool: "git_pull",
16066
+ cause: error instanceof Error ? error : void 0
16067
+ });
15849
16068
  }
15850
16069
  }
15851
16070
  });
@@ -15871,10 +16090,10 @@ Examples:
15871
16090
  path: cwd ?? process.cwd()
15872
16091
  };
15873
16092
  } catch (error) {
15874
- throw new ToolError(
15875
- `Git init failed: ${error instanceof Error ? error.message : String(error)}`,
15876
- { tool: "git_init", cause: error instanceof Error ? error : void 0 }
15877
- );
16093
+ throw new ToolError(enrichGitError("init", error), {
16094
+ tool: "git_init",
16095
+ cause: error instanceof Error ? error : void 0
16096
+ });
15878
16097
  }
15879
16098
  }
15880
16099
  });
@@ -16150,8 +16369,8 @@ var checkAgentCapabilityTool = defineTool({
16150
16369
  var simpleAgentTools = [spawnSimpleAgentTool, checkAgentCapabilityTool];
16151
16370
  async function detectTestFramework2(cwd) {
16152
16371
  try {
16153
- const pkgPath = path15__default.join(cwd, "package.json");
16154
- const pkgContent = await fs14__default.readFile(pkgPath, "utf-8");
16372
+ const pkgPath = path16__default.join(cwd, "package.json");
16373
+ const pkgContent = await fs15__default.readFile(pkgPath, "utf-8");
16155
16374
  const pkg = JSON.parse(pkgContent);
16156
16375
  const deps = {
16157
16376
  ...pkg.dependencies,
@@ -16239,8 +16458,9 @@ Examples:
16239
16458
  duration
16240
16459
  );
16241
16460
  } catch (error) {
16461
+ const msg = error instanceof Error ? error.message : String(error);
16242
16462
  throw new ToolError(
16243
- `Test execution failed: ${error instanceof Error ? error.message : String(error)}`,
16463
+ `Test execution failed: ${msg}. Use command_exists to verify the test framework is installed, or run_script with a custom command.`,
16244
16464
  { tool: "run_tests", cause: error instanceof Error ? error : void 0 }
16245
16465
  );
16246
16466
  }
@@ -16331,13 +16551,13 @@ Examples:
16331
16551
  const projectDir = cwd ?? process.cwd();
16332
16552
  try {
16333
16553
  const coverageLocations = [
16334
- path15__default.join(projectDir, "coverage", "coverage-summary.json"),
16335
- path15__default.join(projectDir, "coverage", "coverage-final.json"),
16336
- path15__default.join(projectDir, ".nyc_output", "coverage-summary.json")
16554
+ path16__default.join(projectDir, "coverage", "coverage-summary.json"),
16555
+ path16__default.join(projectDir, "coverage", "coverage-final.json"),
16556
+ path16__default.join(projectDir, ".nyc_output", "coverage-summary.json")
16337
16557
  ];
16338
16558
  for (const location of coverageLocations) {
16339
16559
  try {
16340
- const content = await fs14__default.readFile(location, "utf-8");
16560
+ const content = await fs15__default.readFile(location, "utf-8");
16341
16561
  const coverage = JSON.parse(content);
16342
16562
  if (coverage.total) {
16343
16563
  return {
@@ -16356,8 +16576,9 @@ Examples:
16356
16576
  });
16357
16577
  } catch (error) {
16358
16578
  if (error instanceof ToolError) throw error;
16579
+ const msg = error instanceof Error ? error.message : String(error);
16359
16580
  throw new ToolError(
16360
- `Failed to read coverage: ${error instanceof Error ? error.message : String(error)}`,
16581
+ `Failed to read coverage: ${msg}. Run run_tests with coverage: true first to generate coverage data.`,
16361
16582
  { tool: "get_coverage", cause: error instanceof Error ? error : void 0 }
16362
16583
  );
16363
16584
  }
@@ -16389,8 +16610,8 @@ Examples:
16389
16610
  var testTools = [runTestsTool, getCoverageTool, runTestFileTool];
16390
16611
  async function detectLinter2(cwd) {
16391
16612
  try {
16392
- const pkgPath = path15__default.join(cwd, "package.json");
16393
- const pkgContent = await fs14__default.readFile(pkgPath, "utf-8");
16613
+ const pkgPath = path16__default.join(cwd, "package.json");
16614
+ const pkgContent = await fs15__default.readFile(pkgPath, "utf-8");
16394
16615
  const pkg = JSON.parse(pkgContent);
16395
16616
  const deps = {
16396
16617
  ...pkg.dependencies,
@@ -16429,7 +16650,9 @@ Examples:
16429
16650
  warnings: 0,
16430
16651
  fixable: 0,
16431
16652
  issues: [],
16432
- score: 100
16653
+ score: null,
16654
+ linter: "none",
16655
+ message: "No linter detected (looked for: eslint, oxlint, biome). Install one or use bash_exec to run a custom linter."
16433
16656
  };
16434
16657
  }
16435
16658
  try {
@@ -16546,7 +16769,7 @@ Examples:
16546
16769
  let totalFunctions = 0;
16547
16770
  let complexFunctions = 0;
16548
16771
  for (const file of targetFiles) {
16549
- const content = await fs14__default.readFile(file, "utf-8");
16772
+ const content = await fs15__default.readFile(file, "utf-8");
16550
16773
  const fileComplexity = analyzeFileComplexity(content, file);
16551
16774
  fileResults.push(fileComplexity);
16552
16775
  totalComplexity += fileComplexity.complexity;
@@ -16569,8 +16792,9 @@ Examples:
16569
16792
  files: fileResults
16570
16793
  };
16571
16794
  } catch (error) {
16795
+ const msg = error instanceof Error ? error.message : String(error);
16572
16796
  throw new ToolError(
16573
- `Complexity analysis failed: ${error instanceof Error ? error.message : String(error)}`,
16797
+ `Complexity analysis failed: ${msg}. Try read_file to inspect the code manually.`,
16574
16798
  { tool: "analyze_complexity", cause: error instanceof Error ? error : void 0 }
16575
16799
  );
16576
16800
  }
@@ -16656,8 +16880,9 @@ Examples:
16656
16880
  const evaluation = await evaluator.evaluate(files);
16657
16881
  return evaluation.scores;
16658
16882
  } catch (error) {
16883
+ const msg = error instanceof Error ? error.message : String(error);
16659
16884
  throw new ToolError(
16660
- `Quality calculation failed: ${error instanceof Error ? error.message : String(error)}`,
16885
+ `Quality calculation failed: ${msg}. Run run_linter and run_tests separately for partial results.`,
16661
16886
  { tool: "calculate_quality", cause: error instanceof Error ? error : void 0 }
16662
16887
  );
16663
16888
  }
@@ -16695,7 +16920,7 @@ Examples:
16695
16920
  caseSensitive,
16696
16921
  wholeWord
16697
16922
  }) {
16698
- const targetPath = searchPath ? path15__default.resolve(searchPath) : process.cwd();
16923
+ const targetPath = searchPath ? path16__default.resolve(searchPath) : process.cwd();
16699
16924
  const matches = [];
16700
16925
  let filesSearched = 0;
16701
16926
  const filesWithMatches = /* @__PURE__ */ new Set();
@@ -16717,7 +16942,7 @@ Examples:
16717
16942
  tool: "grep"
16718
16943
  });
16719
16944
  }
16720
- const stats = await fs14__default.stat(targetPath);
16945
+ const stats = await fs15__default.stat(targetPath);
16721
16946
  let filesToSearch;
16722
16947
  if (stats.isFile()) {
16723
16948
  filesToSearch = [targetPath];
@@ -16739,7 +16964,7 @@ Examples:
16739
16964
  }
16740
16965
  filesSearched++;
16741
16966
  try {
16742
- const content = await fs14__default.readFile(file, "utf-8");
16967
+ const content = await fs15__default.readFile(file, "utf-8");
16743
16968
  const lines = content.split("\n");
16744
16969
  let fileHasMatch = false;
16745
16970
  for (let i = 0; i < lines.length; i++) {
@@ -16762,7 +16987,7 @@ Examples:
16762
16987
  contextAfter.push(lines[j] ?? "");
16763
16988
  }
16764
16989
  matches.push({
16765
- file: path15__default.relative(process.cwd(), file),
16990
+ file: path16__default.relative(process.cwd(), file),
16766
16991
  line: i + 1,
16767
16992
  column: match.index + 1,
16768
16993
  content: line,
@@ -16813,8 +17038,8 @@ Examples:
16813
17038
  }),
16814
17039
  async execute({ file, pattern, caseSensitive }) {
16815
17040
  try {
16816
- const absolutePath = path15__default.resolve(file);
16817
- const content = await fs14__default.readFile(absolutePath, "utf-8");
17041
+ const absolutePath = path16__default.resolve(file);
17042
+ const content = await fs15__default.readFile(absolutePath, "utf-8");
16818
17043
  const lines = content.split("\n");
16819
17044
  const matches = [];
16820
17045
  const flags = caseSensitive ? "" : "i";
@@ -16830,6 +17055,11 @@ Examples:
16830
17055
  }
16831
17056
  return { matches, count: matches.length };
16832
17057
  } catch (error) {
17058
+ if (error.code === "ENOENT") {
17059
+ throw new ToolError(`File not found: ${file}. Use glob to find the correct path.`, {
17060
+ tool: "find_in_file"
17061
+ });
17062
+ }
16833
17063
  throw new ToolError(
16834
17064
  `Find in file failed: ${error instanceof Error ? error.message : String(error)}`,
16835
17065
  { tool: "find_in_file", cause: error instanceof Error ? error : void 0 }
@@ -16981,6 +17211,22 @@ Examples:
16981
17211
  var httpTools = [httpFetchTool, httpJsonTool];
16982
17212
  var DEFAULT_TIMEOUT_MS3 = 6e5;
16983
17213
  var MAX_OUTPUT_SIZE2 = 2 * 1024 * 1024;
17214
+ function getBuildHint(stderr, tool) {
17215
+ if (/MODULE_NOT_FOUND|Cannot find module/i.test(stderr))
17216
+ return "A dependency is missing. Run install_deps first.";
17217
+ if (/ENOENT|no such file/i.test(stderr))
17218
+ return "A file or directory was not found. Use glob or list_dir to verify paths.";
17219
+ if (/EACCES|permission denied/i.test(stderr)) return "Permission denied. Check file permissions.";
17220
+ if (/SyntaxError|Unexpected token/i.test(stderr))
17221
+ return "Syntax error in the code. Use read_file to check the problematic file.";
17222
+ if (/TS\d{4}:/i.test(stderr))
17223
+ return "TypeScript compilation error. Read the error details above and use edit_file to fix.";
17224
+ if (/ERR!/i.test(stderr) && tool === "install_deps")
17225
+ return "Package install failed. Check if the package name is correct or if there are network issues.";
17226
+ if (/No Makefile/i.test(stderr) || /No rule to make target/i.test(stderr))
17227
+ return "Makefile target not found. Check available targets with 'make -n' or list_dir.";
17228
+ return `${tool} failed. Check stderr output above for details.`;
17229
+ }
16984
17230
  async function detectPackageManager(cwd) {
16985
17231
  const lockfiles = [
16986
17232
  { file: "pnpm-lock.yaml", pm: "pnpm" },
@@ -16990,7 +17236,7 @@ async function detectPackageManager(cwd) {
16990
17236
  ];
16991
17237
  for (const { file, pm } of lockfiles) {
16992
17238
  try {
16993
- await fs14__default.access(path15__default.join(cwd, file));
17239
+ await fs15__default.access(path16__default.join(cwd, file));
16994
17240
  return pm;
16995
17241
  } catch {
16996
17242
  }
@@ -17073,7 +17319,7 @@ ${message}
17073
17319
  heartbeat.activity();
17074
17320
  });
17075
17321
  const result = await subprocess;
17076
- return {
17322
+ const buildResult = {
17077
17323
  success: result.exitCode === 0,
17078
17324
  stdout: truncateOutput2(stdoutBuffer),
17079
17325
  stderr: truncateOutput2(stderrBuffer),
@@ -17081,6 +17327,10 @@ ${message}
17081
17327
  duration: performance.now() - startTime,
17082
17328
  packageManager: pm
17083
17329
  };
17330
+ if (!buildResult.success) {
17331
+ buildResult.hint = getBuildHint(stderrBuffer || stdoutBuffer, "run_script");
17332
+ }
17333
+ return buildResult;
17084
17334
  } catch (error) {
17085
17335
  if (error.timedOut) {
17086
17336
  throw new TimeoutError(`Script '${script}' timed out after ${timeoutMs}ms`, {
@@ -17194,7 +17444,7 @@ ${message}
17194
17444
  heartbeat.activity();
17195
17445
  });
17196
17446
  const result = await subprocess;
17197
- return {
17447
+ const buildResult = {
17198
17448
  success: result.exitCode === 0,
17199
17449
  stdout: truncateOutput2(stdoutBuffer),
17200
17450
  stderr: truncateOutput2(stderrBuffer),
@@ -17202,6 +17452,10 @@ ${message}
17202
17452
  duration: performance.now() - startTime,
17203
17453
  packageManager: pm
17204
17454
  };
17455
+ if (!buildResult.success) {
17456
+ buildResult.hint = getBuildHint(stderrBuffer || stdoutBuffer, "install_deps");
17457
+ }
17458
+ return buildResult;
17205
17459
  } catch (error) {
17206
17460
  if (error.timedOut) {
17207
17461
  throw new TimeoutError(`Install timed out after ${timeoutMs}ms`, {
@@ -17255,7 +17509,7 @@ ${message}
17255
17509
  });
17256
17510
  try {
17257
17511
  try {
17258
- await fs14__default.access(path15__default.join(projectDir, "Makefile"));
17512
+ await fs15__default.access(path16__default.join(projectDir, "Makefile"));
17259
17513
  } catch {
17260
17514
  throw new ToolError("No Makefile found in directory", { tool: "make" });
17261
17515
  }
@@ -17292,13 +17546,17 @@ ${message}
17292
17546
  heartbeat.activity();
17293
17547
  });
17294
17548
  const result = await subprocess;
17295
- return {
17549
+ const buildResult = {
17296
17550
  success: result.exitCode === 0,
17297
17551
  stdout: truncateOutput2(stdoutBuffer),
17298
17552
  stderr: truncateOutput2(stderrBuffer),
17299
17553
  exitCode: result.exitCode ?? 0,
17300
17554
  duration: performance.now() - startTime
17301
17555
  };
17556
+ if (!buildResult.success) {
17557
+ buildResult.hint = getBuildHint(stderrBuffer || stdoutBuffer, "make");
17558
+ }
17559
+ return buildResult;
17302
17560
  } catch (error) {
17303
17561
  if (error instanceof ToolError) throw error;
17304
17562
  if (error.timedOut) {
@@ -17391,13 +17649,17 @@ ${message}
17391
17649
  heartbeat.activity();
17392
17650
  });
17393
17651
  const result = await subprocess;
17394
- return {
17652
+ const buildResult = {
17395
17653
  success: result.exitCode === 0,
17396
17654
  stdout: truncateOutput2(stdoutBuffer),
17397
17655
  stderr: truncateOutput2(stderrBuffer),
17398
17656
  exitCode: result.exitCode ?? 0,
17399
17657
  duration: performance.now() - startTime
17400
17658
  };
17659
+ if (!buildResult.success) {
17660
+ buildResult.hint = getBuildHint(stderrBuffer || stdoutBuffer, "tsc");
17661
+ }
17662
+ return buildResult;
17401
17663
  } catch (error) {
17402
17664
  if (error.timedOut) {
17403
17665
  throw new TimeoutError(`TypeScript compile timed out after ${timeoutMs}ms`, {
@@ -17452,7 +17714,7 @@ z.object({
17452
17714
  });
17453
17715
 
17454
17716
  // src/cli/repl/session.ts
17455
- path15__default.dirname(CONFIG_PATHS.trustedTools);
17717
+ path16__default.dirname(CONFIG_PATHS.trustedTools);
17456
17718
  CONFIG_PATHS.trustedTools;
17457
17719
 
17458
17720
  // src/cli/repl/recommended-permissions.ts
@@ -17968,9 +18230,10 @@ async function searchDuckDuckGo(query, maxResults, timeout) {
17968
18230
  });
17969
18231
  clearTimeout(timeoutId);
17970
18232
  if (!response.ok) {
17971
- throw new ToolError(`DuckDuckGo search failed with status ${response.status}`, {
17972
- tool: "web_search"
17973
- });
18233
+ throw new ToolError(
18234
+ `DuckDuckGo search failed with status ${response.status}. Try a different search engine (brave, serpapi) or simplify the query.`,
18235
+ { tool: "web_search" }
18236
+ );
17974
18237
  }
17975
18238
  const html = await response.text();
17976
18239
  return parseDuckDuckGoResults(html, maxResults);
@@ -18001,9 +18264,10 @@ async function searchBrave(query, maxResults, timeout) {
18001
18264
  });
18002
18265
  clearTimeout(timeoutId);
18003
18266
  if (!response.ok) {
18004
- throw new ToolError(`Brave search failed with status ${response.status}`, {
18005
- tool: "web_search"
18006
- });
18267
+ throw new ToolError(
18268
+ `Brave search failed with status ${response.status}. Try a different search engine (duckduckgo, serpapi) or check your BRAVE_SEARCH_API_KEY.`,
18269
+ { tool: "web_search" }
18270
+ );
18007
18271
  }
18008
18272
  const data = await response.json();
18009
18273
  return (data.web?.results ?? []).slice(0, maxResults).map((r) => ({
@@ -18037,9 +18301,10 @@ async function searchSerpApi(query, maxResults, timeout) {
18037
18301
  });
18038
18302
  clearTimeout(timeoutId);
18039
18303
  if (!response.ok) {
18040
- throw new ToolError(`SerpAPI search failed with status ${response.status}`, {
18041
- tool: "web_search"
18042
- });
18304
+ throw new ToolError(
18305
+ `SerpAPI search failed with status ${response.status}. Try a different search engine (duckduckgo, brave) or check your SERPAPI_KEY.`,
18306
+ { tool: "web_search" }
18307
+ );
18043
18308
  }
18044
18309
  const data = await response.json();
18045
18310
  return (data.organic_results ?? []).slice(0, maxResults).map((r) => ({
@@ -18124,6 +18389,27 @@ var PRIVATE_IP_PATTERNS = [
18124
18389
  /^https?:\/\/0\.0\.0\.0/,
18125
18390
  /^https?:\/\/\[::1\]/
18126
18391
  ];
18392
+ function getHttpErrorHint(status) {
18393
+ switch (status) {
18394
+ case 401:
18395
+ case 403:
18396
+ return "\nThis page requires authentication. Try using web_search to find a publicly accessible alternative.";
18397
+ case 404:
18398
+ return "\nPage not found. The URL may be outdated or misspelled. Try web_search to find the correct URL.";
18399
+ case 429:
18400
+ return "\nRate limited. Wait a moment before retrying, or try an alternative source.";
18401
+ case 500:
18402
+ case 502:
18403
+ case 503:
18404
+ case 504:
18405
+ return "\nServer error (temporary). Try again in a moment, or use web_search to find an alternative source.";
18406
+ default:
18407
+ if (status >= 400 && status < 500) {
18408
+ return "\nClient error. Check the URL is correct or try web_search to find the right page.";
18409
+ }
18410
+ return "";
18411
+ }
18412
+ }
18127
18413
  function validateUrl(url) {
18128
18414
  for (const scheme of BLOCKED_SCHEMES) {
18129
18415
  if (url.toLowerCase().startsWith(scheme)) {
@@ -18342,7 +18628,8 @@ Examples:
18342
18628
  });
18343
18629
  clearTimeout(timeoutId);
18344
18630
  if (!response.ok) {
18345
- throw new ToolError(`HTTP ${response.status}: ${response.statusText}`, {
18631
+ const hint = getHttpErrorHint(response.status);
18632
+ throw new ToolError(`HTTP ${response.status}: ${response.statusText} \u2014 ${url}${hint}`, {
18346
18633
  tool: "web_fetch"
18347
18634
  });
18348
18635
  }
@@ -18870,25 +19157,31 @@ Examples:
18870
19157
  rendered: true
18871
19158
  };
18872
19159
  } catch (error) {
18873
- throw new ToolError(
18874
- `Diff failed: ${error instanceof Error ? error.message : String(error)}`,
18875
- { tool: "show_diff", cause: error instanceof Error ? error : void 0 }
18876
- );
19160
+ const msg = error instanceof Error ? error.message : String(error);
19161
+ let hint = `Diff failed: ${msg}`;
19162
+ if (/not a git repository/i.test(msg))
19163
+ hint = "Not a git repository. Use list_dir to verify you're in the right directory.";
19164
+ else if (/unknown revision|bad revision/i.test(msg))
19165
+ hint = `Reference not found: ${msg}. Use git_log or git_branch to find valid refs.`;
19166
+ throw new ToolError(hint, {
19167
+ tool: "show_diff",
19168
+ cause: error instanceof Error ? error : void 0
19169
+ });
18877
19170
  }
18878
19171
  }
18879
19172
  });
18880
19173
  var diffTools = [showDiffTool];
18881
19174
  async function fileExists(filePath) {
18882
19175
  try {
18883
- await fs14__default.access(filePath);
19176
+ await fs15__default.access(filePath);
18884
19177
  return true;
18885
19178
  } catch {
18886
19179
  return false;
18887
19180
  }
18888
19181
  }
18889
- async function fileExists2(path38) {
19182
+ async function fileExists2(path39) {
18890
19183
  try {
18891
- await access(path38);
19184
+ await access(path39);
18892
19185
  return true;
18893
19186
  } catch {
18894
19187
  return false;
@@ -18978,7 +19271,7 @@ async function detectMaturity(cwd) {
18978
19271
  if (!hasLintConfig && hasPackageJson) {
18979
19272
  try {
18980
19273
  const pkgRaw = await import('fs/promises').then(
18981
- (fs36) => fs36.readFile(join(cwd, "package.json"), "utf-8")
19274
+ (fs37) => fs37.readFile(join(cwd, "package.json"), "utf-8")
18982
19275
  );
18983
19276
  const pkg = JSON.parse(pkgRaw);
18984
19277
  if (pkg.scripts?.lint || pkg.scripts?.["lint:fix"]) {
@@ -19073,6 +19366,7 @@ function getGit3(cwd) {
19073
19366
  }
19074
19367
  async function getDiff(git, baseBranch, includeUncommitted) {
19075
19368
  const diffs = [];
19369
+ const warnings = [];
19076
19370
  try {
19077
19371
  const branchDiff = await git.diff([`${baseBranch}...HEAD`]);
19078
19372
  if (branchDiff) diffs.push(branchDiff);
@@ -19081,6 +19375,7 @@ async function getDiff(git, baseBranch, includeUncommitted) {
19081
19375
  const directDiff = await git.diff([baseBranch]);
19082
19376
  if (directDiff) diffs.push(directDiff);
19083
19377
  } catch {
19378
+ warnings.push(`Could not diff against base branch '${baseBranch}' \u2014 it may not exist.`);
19084
19379
  }
19085
19380
  }
19086
19381
  if (includeUncommitted) {
@@ -19088,14 +19383,16 @@ async function getDiff(git, baseBranch, includeUncommitted) {
19088
19383
  const uncommitted = await git.diff();
19089
19384
  if (uncommitted) diffs.push(uncommitted);
19090
19385
  } catch {
19386
+ warnings.push("Could not read unstaged changes.");
19091
19387
  }
19092
19388
  try {
19093
19389
  const staged = await git.diff(["--staged"]);
19094
19390
  if (staged) diffs.push(staged);
19095
19391
  } catch {
19392
+ warnings.push("Could not read staged changes.");
19096
19393
  }
19097
19394
  }
19098
- return diffs.join("\n");
19395
+ return { raw: diffs.join("\n"), warnings };
19099
19396
  }
19100
19397
  function analyzePatterns(diff) {
19101
19398
  const findings = [];
@@ -19143,7 +19440,7 @@ async function checkTestCoverage(diff, cwd) {
19143
19440
  );
19144
19441
  if (!hasTestChange) {
19145
19442
  const ext = src.path.match(/\.(ts|tsx|js|jsx)$/)?.[0] ?? ".ts";
19146
- const testExists = await fileExists(path15__default.join(cwd, `${baseName}.test${ext}`)) || await fileExists(path15__default.join(cwd, `${baseName}.spec${ext}`));
19443
+ const testExists = await fileExists(path16__default.join(cwd, `${baseName}.test${ext}`)) || await fileExists(path16__default.join(cwd, `${baseName}.spec${ext}`));
19147
19444
  if (testExists) {
19148
19445
  if (src.additions >= TEST_COVERAGE_LARGE_CHANGE_THRESHOLD) {
19149
19446
  findings.push({
@@ -19288,10 +19585,14 @@ Examples:
19288
19585
  try {
19289
19586
  const status = await git.status();
19290
19587
  const currentBranch = status.current ?? "HEAD";
19291
- const rawDiff = await getDiff(git, baseBranch, includeUncommitted);
19588
+ const { raw: rawDiff, warnings: diffWarnings } = await getDiff(
19589
+ git,
19590
+ baseBranch,
19591
+ includeUncommitted
19592
+ );
19292
19593
  const diff = parseDiff(rawDiff);
19293
19594
  if (diff.files.length === 0) {
19294
- return {
19595
+ const emptyResult = {
19295
19596
  summary: {
19296
19597
  branch: currentBranch,
19297
19598
  baseBranch,
@@ -19305,6 +19606,10 @@ Examples:
19305
19606
  maturity: "new",
19306
19607
  diff
19307
19608
  };
19609
+ if (diffWarnings.length > 0) {
19610
+ emptyResult.warnings = diffWarnings;
19611
+ }
19612
+ return emptyResult;
19308
19613
  }
19309
19614
  const maturityInfo = await detectMaturity(projectDir);
19310
19615
  const maturity = maturityInfo.level;
@@ -19326,6 +19631,7 @@ Examples:
19326
19631
  }
19327
19632
  }
19328
19633
  } catch {
19634
+ diffWarnings.push("Linter not available \u2014 code style was not checked.");
19329
19635
  }
19330
19636
  }
19331
19637
  allFindings.push(...getMaturityRecommendations(maturity, diff));
@@ -19338,7 +19644,7 @@ Examples:
19338
19644
  (f) => f.severity === "minor" || f.severity === "info"
19339
19645
  );
19340
19646
  const status_result = required.some((f) => f.severity === "critical") ? "needs_work" : required.length > 0 ? "needs_work" : "approved";
19341
- return {
19647
+ const result = {
19342
19648
  summary: {
19343
19649
  branch: currentBranch,
19344
19650
  baseBranch,
@@ -19352,6 +19658,10 @@ Examples:
19352
19658
  maturity,
19353
19659
  diff
19354
19660
  };
19661
+ if (diffWarnings.length > 0) {
19662
+ result.warnings = diffWarnings;
19663
+ }
19664
+ return result;
19355
19665
  } catch (error) {
19356
19666
  throw new ToolError(
19357
19667
  `Code review failed: ${error instanceof Error ? error.message : String(error)}`,
@@ -19361,8 +19671,8 @@ Examples:
19361
19671
  }
19362
19672
  });
19363
19673
  var reviewTools = [reviewCodeTool];
19364
- var fs23 = await import('fs/promises');
19365
- var path25 = await import('path');
19674
+ var fs24 = await import('fs/promises');
19675
+ var path26 = await import('path');
19366
19676
  var { glob: glob14 } = await import('glob');
19367
19677
  var DEFAULT_MAX_FILES = 200;
19368
19678
  var LANGUAGE_EXTENSIONS = {
@@ -19388,7 +19698,7 @@ var DEFAULT_EXCLUDES = [
19388
19698
  "**/*.d.ts"
19389
19699
  ];
19390
19700
  function detectLanguage3(filePath) {
19391
- const ext = path25.extname(filePath).toLowerCase();
19701
+ const ext = path26.extname(filePath).toLowerCase();
19392
19702
  for (const [lang, extensions] of Object.entries(LANGUAGE_EXTENSIONS)) {
19393
19703
  if (extensions.includes(ext)) return lang;
19394
19704
  }
@@ -19797,9 +20107,9 @@ Examples:
19797
20107
  }),
19798
20108
  async execute({ path: rootPath, include, exclude, languages, maxFiles, depth }) {
19799
20109
  const startTime = performance.now();
19800
- const absPath = path25.resolve(rootPath);
20110
+ const absPath = path26.resolve(rootPath);
19801
20111
  try {
19802
- const stat2 = await fs23.stat(absPath);
20112
+ const stat2 = await fs24.stat(absPath);
19803
20113
  if (!stat2.isDirectory()) {
19804
20114
  throw new ToolError(`Path is not a directory: ${absPath}`, {
19805
20115
  tool: "codebase_map"
@@ -19836,14 +20146,14 @@ Examples:
19836
20146
  let totalDefinitions = 0;
19837
20147
  let exportedSymbols = 0;
19838
20148
  for (const file of limitedFiles) {
19839
- const fullPath = path25.join(absPath, file);
20149
+ const fullPath = path26.join(absPath, file);
19840
20150
  const language = detectLanguage3(file);
19841
20151
  if (!language) continue;
19842
20152
  if (languages && !languages.includes(language)) {
19843
20153
  continue;
19844
20154
  }
19845
20155
  try {
19846
- const content = await fs23.readFile(fullPath, "utf-8");
20156
+ const content = await fs24.readFile(fullPath, "utf-8");
19847
20157
  const lineCount = content.split("\n").length;
19848
20158
  const parsed = parseFile(content, language);
19849
20159
  const definitions = depth === "overview" ? parsed.definitions.filter((d) => d.exported) : parsed.definitions;
@@ -19876,23 +20186,23 @@ Examples:
19876
20186
  });
19877
20187
  var codebaseMapTools = [codebaseMapTool];
19878
20188
  init_paths();
19879
- var fs24 = await import('fs/promises');
19880
- var path26 = await import('path');
20189
+ var fs25 = await import('fs/promises');
20190
+ var path27 = await import('path');
19881
20191
  var crypto2 = await import('crypto');
19882
- var GLOBAL_MEMORIES_DIR = path26.join(COCO_HOME, "memories");
20192
+ var GLOBAL_MEMORIES_DIR = path27.join(COCO_HOME, "memories");
19883
20193
  var PROJECT_MEMORIES_DIR = ".coco/memories";
19884
20194
  var DEFAULT_MAX_MEMORIES = 1e3;
19885
20195
  async function ensureDir(dirPath) {
19886
- await fs24.mkdir(dirPath, { recursive: true });
20196
+ await fs25.mkdir(dirPath, { recursive: true });
19887
20197
  }
19888
20198
  function getMemoriesDir(scope) {
19889
20199
  return scope === "global" ? GLOBAL_MEMORIES_DIR : PROJECT_MEMORIES_DIR;
19890
20200
  }
19891
20201
  async function loadIndex(scope) {
19892
20202
  const dir = getMemoriesDir(scope);
19893
- const indexPath = path26.join(dir, "index.json");
20203
+ const indexPath = path27.join(dir, "index.json");
19894
20204
  try {
19895
- const content = await fs24.readFile(indexPath, "utf-8");
20205
+ const content = await fs25.readFile(indexPath, "utf-8");
19896
20206
  return JSON.parse(content);
19897
20207
  } catch {
19898
20208
  return [];
@@ -19901,14 +20211,14 @@ async function loadIndex(scope) {
19901
20211
  async function saveIndex(scope, index) {
19902
20212
  const dir = getMemoriesDir(scope);
19903
20213
  await ensureDir(dir);
19904
- const indexPath = path26.join(dir, "index.json");
19905
- await fs24.writeFile(indexPath, JSON.stringify(index, null, 2), "utf-8");
20214
+ const indexPath = path27.join(dir, "index.json");
20215
+ await fs25.writeFile(indexPath, JSON.stringify(index, null, 2), "utf-8");
19906
20216
  }
19907
20217
  async function loadMemory(scope, id) {
19908
20218
  const dir = getMemoriesDir(scope);
19909
- const memPath = path26.join(dir, `${id}.json`);
20219
+ const memPath = path27.join(dir, `${id}.json`);
19910
20220
  try {
19911
- const content = await fs24.readFile(memPath, "utf-8");
20221
+ const content = await fs25.readFile(memPath, "utf-8");
19912
20222
  return JSON.parse(content);
19913
20223
  } catch {
19914
20224
  return null;
@@ -19917,8 +20227,8 @@ async function loadMemory(scope, id) {
19917
20227
  async function saveMemory(scope, memory) {
19918
20228
  const dir = getMemoriesDir(scope);
19919
20229
  await ensureDir(dir);
19920
- const memPath = path26.join(dir, `${memory.id}.json`);
19921
- await fs24.writeFile(memPath, JSON.stringify(memory, null, 2), "utf-8");
20230
+ const memPath = path27.join(dir, `${memory.id}.json`);
20231
+ await fs25.writeFile(memPath, JSON.stringify(memory, null, 2), "utf-8");
19922
20232
  }
19923
20233
  var createMemoryTool = defineTool({
19924
20234
  name: "create_memory",
@@ -20070,17 +20380,17 @@ Examples:
20070
20380
  }
20071
20381
  });
20072
20382
  var memoryTools = [createMemoryTool, recallMemoryTool, listMemoriesTool];
20073
- var fs25 = await import('fs/promises');
20383
+ var fs26 = await import('fs/promises');
20074
20384
  var crypto3 = await import('crypto');
20075
20385
  var CHECKPOINT_FILE = ".coco/checkpoints.json";
20076
20386
  var DEFAULT_MAX_CHECKPOINTS = 50;
20077
20387
  var STASH_PREFIX = "coco-cp";
20078
20388
  async function ensureCocoDir() {
20079
- await fs25.mkdir(".coco", { recursive: true });
20389
+ await fs26.mkdir(".coco", { recursive: true });
20080
20390
  }
20081
20391
  async function loadCheckpoints() {
20082
20392
  try {
20083
- const content = await fs25.readFile(CHECKPOINT_FILE, "utf-8");
20393
+ const content = await fs26.readFile(CHECKPOINT_FILE, "utf-8");
20084
20394
  return JSON.parse(content);
20085
20395
  } catch {
20086
20396
  return [];
@@ -20088,7 +20398,7 @@ async function loadCheckpoints() {
20088
20398
  }
20089
20399
  async function saveCheckpoints(checkpoints) {
20090
20400
  await ensureCocoDir();
20091
- await fs25.writeFile(CHECKPOINT_FILE, JSON.stringify(checkpoints, null, 2), "utf-8");
20401
+ await fs26.writeFile(CHECKPOINT_FILE, JSON.stringify(checkpoints, null, 2), "utf-8");
20092
20402
  }
20093
20403
  async function execGit(args) {
20094
20404
  const { execaCommand } = await import('execa');
@@ -20099,10 +20409,11 @@ async function execGit(args) {
20099
20409
  });
20100
20410
  return result.stdout;
20101
20411
  } catch (error) {
20102
- throw new ToolError(
20103
- `Git command failed: git ${args.join(" ")}: ${error instanceof Error ? error.message : String(error)}`,
20104
- { tool: "checkpoint" }
20105
- );
20412
+ const msg = error instanceof Error ? error.message : String(error);
20413
+ let hint = `Git command failed (${args[0] ?? "unknown"}): ${msg}`;
20414
+ if (/not a git repository/i.test(msg))
20415
+ hint = "Not a git repository. Checkpoints require a git repo \u2014 run git_init first.";
20416
+ throw new ToolError(hint, { tool: "checkpoint" });
20106
20417
  }
20107
20418
  }
20108
20419
  async function getChangedFiles() {
@@ -20220,8 +20531,9 @@ Examples:
20220
20531
  message: `Restored checkpoint '${checkpoint.description}' (${checkpoint.fileCount} files)`
20221
20532
  };
20222
20533
  } catch (error) {
20534
+ const msg = error instanceof Error ? error.message : String(error);
20223
20535
  throw new ToolError(
20224
- `Failed to restore checkpoint: ${error instanceof Error ? error.message : String(error)}`,
20536
+ `Failed to restore checkpoint: ${msg}. Use list_checkpoints to see available checkpoints.`,
20225
20537
  { tool: "restore_checkpoint" }
20226
20538
  );
20227
20539
  }
@@ -20248,8 +20560,8 @@ Examples:
20248
20560
  }
20249
20561
  });
20250
20562
  var checkpointTools = [createCheckpointTool, restoreCheckpointTool, listCheckpointsTool];
20251
- var fs26 = await import('fs/promises');
20252
- var path27 = await import('path');
20563
+ var fs27 = await import('fs/promises');
20564
+ var path28 = await import('path');
20253
20565
  var { glob: glob15 } = await import('glob');
20254
20566
  var INDEX_DIR = ".coco/search-index";
20255
20567
  var DEFAULT_CHUNK_SIZE = 20;
@@ -20355,6 +20667,7 @@ function simpleEmbedding(text) {
20355
20667
  return vector;
20356
20668
  }
20357
20669
  var embedFn = null;
20670
+ var usingFallbackEmbedding = false;
20358
20671
  async function getEmbedding(text) {
20359
20672
  if (!embedFn) {
20360
20673
  try {
@@ -20369,26 +20682,27 @@ async function getEmbedding(text) {
20369
20682
  };
20370
20683
  } catch {
20371
20684
  embedFn = async (t) => simpleEmbedding(t);
20685
+ usingFallbackEmbedding = true;
20372
20686
  }
20373
20687
  }
20374
20688
  return embedFn(text);
20375
20689
  }
20376
20690
  async function loadIndex2(indexDir) {
20377
20691
  try {
20378
- const indexPath = path27.join(indexDir, "index.json");
20379
- const content = await fs26.readFile(indexPath, "utf-8");
20692
+ const indexPath = path28.join(indexDir, "index.json");
20693
+ const content = await fs27.readFile(indexPath, "utf-8");
20380
20694
  return JSON.parse(content);
20381
20695
  } catch {
20382
20696
  return null;
20383
20697
  }
20384
20698
  }
20385
20699
  async function saveIndex2(indexDir, index) {
20386
- await fs26.mkdir(indexDir, { recursive: true });
20387
- const indexPath = path27.join(indexDir, "index.json");
20388
- await fs26.writeFile(indexPath, JSON.stringify(index), "utf-8");
20700
+ await fs27.mkdir(indexDir, { recursive: true });
20701
+ const indexPath = path28.join(indexDir, "index.json");
20702
+ await fs27.writeFile(indexPath, JSON.stringify(index), "utf-8");
20389
20703
  }
20390
20704
  function isBinary(filePath) {
20391
- return BINARY_EXTENSIONS.has(path27.extname(filePath).toLowerCase());
20705
+ return BINARY_EXTENSIONS.has(path28.extname(filePath).toLowerCase());
20392
20706
  }
20393
20707
  var semanticSearchTool = defineTool({
20394
20708
  name: "semantic_search",
@@ -20413,9 +20727,10 @@ Examples:
20413
20727
  const effectivePath = rootPath ?? ".";
20414
20728
  const effectiveMaxResults = maxResults ?? 10;
20415
20729
  const effectiveThreshold = threshold ?? 0.3;
20416
- const absPath = path27.resolve(effectivePath);
20417
- const indexDir = path27.join(absPath, INDEX_DIR);
20730
+ const absPath = path28.resolve(effectivePath);
20731
+ const indexDir = path28.join(absPath, INDEX_DIR);
20418
20732
  let index = reindex ? null : await loadIndex2(indexDir);
20733
+ let warnings = [];
20419
20734
  if (!index) {
20420
20735
  const pattern = include ?? "**/*";
20421
20736
  const files = await glob15(pattern, {
@@ -20425,12 +20740,14 @@ Examples:
20425
20740
  absolute: false
20426
20741
  });
20427
20742
  const chunks = [];
20743
+ let skippedFiles = 0;
20744
+ let indexSaveWarning = "";
20428
20745
  for (const file of files) {
20429
20746
  if (isBinary(file)) continue;
20430
- const fullPath = path27.join(absPath, file);
20747
+ const fullPath = path28.join(absPath, file);
20431
20748
  try {
20432
- const stat2 = await fs26.stat(fullPath);
20433
- const content = await fs26.readFile(fullPath, "utf-8");
20749
+ const stat2 = await fs27.stat(fullPath);
20750
+ const content = await fs27.readFile(fullPath, "utf-8");
20434
20751
  if (content.length > 1e5) continue;
20435
20752
  const fileChunks = chunkContent(content, DEFAULT_CHUNK_SIZE);
20436
20753
  for (const chunk of fileChunks) {
@@ -20445,6 +20762,7 @@ Examples:
20445
20762
  });
20446
20763
  }
20447
20764
  } catch {
20765
+ skippedFiles++;
20448
20766
  continue;
20449
20767
  }
20450
20768
  }
@@ -20457,6 +20775,18 @@ Examples:
20457
20775
  try {
20458
20776
  await saveIndex2(indexDir, index);
20459
20777
  } catch {
20778
+ indexSaveWarning = "Index could not be saved to disk \u2014 next search will rebuild it.";
20779
+ }
20780
+ if (usingFallbackEmbedding) {
20781
+ warnings.push(
20782
+ "Using basic text matching (transformer model unavailable). Results may be less accurate."
20783
+ );
20784
+ }
20785
+ if (skippedFiles > 0) {
20786
+ warnings.push(`${skippedFiles} file(s) could not be read (binary or permission issues).`);
20787
+ }
20788
+ if (indexSaveWarning) {
20789
+ warnings.push(indexSaveWarning);
20460
20790
  }
20461
20791
  }
20462
20792
  const queryVector = await getEmbedding(query);
@@ -20480,17 +20810,21 @@ Examples:
20480
20810
  const ageMs = Date.now() - indexDate.getTime();
20481
20811
  const ageMinutes = Math.round(ageMs / 6e4);
20482
20812
  const indexAge = ageMinutes < 60 ? `${ageMinutes}m ago` : `${Math.round(ageMinutes / 60)}h ago`;
20483
- return {
20813
+ const output = {
20484
20814
  results,
20485
20815
  totalIndexed: index.chunks.length,
20486
20816
  indexAge,
20487
20817
  duration: performance.now() - startTime
20488
20818
  };
20819
+ if (warnings.length > 0) {
20820
+ output.warning = warnings.join(" ");
20821
+ }
20822
+ return output;
20489
20823
  }
20490
20824
  });
20491
20825
  var semanticSearchTools = [semanticSearchTool];
20492
- var fs27 = await import('fs/promises');
20493
- var path28 = await import('path');
20826
+ var fs28 = await import('fs/promises');
20827
+ var path29 = await import('path');
20494
20828
  var { glob: glob16 } = await import('glob');
20495
20829
  async function parseClassRelationships(rootPath, include) {
20496
20830
  const pattern = include ?? "**/*.{ts,tsx,js,jsx}";
@@ -20503,7 +20837,7 @@ async function parseClassRelationships(rootPath, include) {
20503
20837
  const interfaces = [];
20504
20838
  for (const file of files.slice(0, 100)) {
20505
20839
  try {
20506
- const content = await fs27.readFile(path28.join(rootPath, file), "utf-8");
20840
+ const content = await fs28.readFile(path29.join(rootPath, file), "utf-8");
20507
20841
  const lines = content.split("\n");
20508
20842
  for (let i = 0; i < lines.length; i++) {
20509
20843
  const line = lines[i];
@@ -20622,14 +20956,14 @@ async function generateClassDiagram(rootPath, include) {
20622
20956
  };
20623
20957
  }
20624
20958
  async function generateArchitectureDiagram(rootPath) {
20625
- const entries = await fs27.readdir(rootPath, { withFileTypes: true });
20959
+ const entries = await fs28.readdir(rootPath, { withFileTypes: true });
20626
20960
  const dirs = entries.filter(
20627
20961
  (e) => e.isDirectory() && !e.name.startsWith(".") && !["node_modules", "dist", "build", "coverage", "__pycache__", "target"].includes(e.name)
20628
20962
  );
20629
20963
  const lines = ["graph TD"];
20630
20964
  let nodeCount = 0;
20631
20965
  let edgeCount = 0;
20632
- const rootName = path28.basename(rootPath);
20966
+ const rootName = path29.basename(rootPath);
20633
20967
  lines.push(` ROOT["${rootName}"]`);
20634
20968
  nodeCount++;
20635
20969
  for (const dir of dirs) {
@@ -20639,7 +20973,7 @@ async function generateArchitectureDiagram(rootPath) {
20639
20973
  nodeCount++;
20640
20974
  edgeCount++;
20641
20975
  try {
20642
- const subEntries = await fs27.readdir(path28.join(rootPath, dir.name), {
20976
+ const subEntries = await fs28.readdir(path29.join(rootPath, dir.name), {
20643
20977
  withFileTypes: true
20644
20978
  });
20645
20979
  const subDirs = subEntries.filter(
@@ -20762,7 +21096,7 @@ Examples:
20762
21096
  tool: "generate_diagram"
20763
21097
  });
20764
21098
  }
20765
- const absPath = rootPath ? path28.resolve(rootPath) : process.cwd();
21099
+ const absPath = rootPath ? path29.resolve(rootPath) : process.cwd();
20766
21100
  switch (type) {
20767
21101
  case "class":
20768
21102
  return generateClassDiagram(absPath, include);
@@ -20823,8 +21157,8 @@ Examples:
20823
21157
  }
20824
21158
  });
20825
21159
  var diagramTools = [generateDiagramTool];
20826
- var fs28 = await import('fs/promises');
20827
- var path29 = await import('path');
21160
+ var fs29 = await import('fs/promises');
21161
+ var path30 = await import('path');
20828
21162
  var DEFAULT_MAX_PAGES = 20;
20829
21163
  var MAX_FILE_SIZE = 50 * 1024 * 1024;
20830
21164
  function parsePageRange(rangeStr, totalPages) {
@@ -20859,9 +21193,9 @@ Examples:
20859
21193
  }),
20860
21194
  async execute({ path: filePath, pages, maxPages }) {
20861
21195
  const startTime = performance.now();
20862
- const absPath = path29.resolve(filePath);
21196
+ const absPath = path30.resolve(filePath);
20863
21197
  try {
20864
- const stat2 = await fs28.stat(absPath);
21198
+ const stat2 = await fs29.stat(absPath);
20865
21199
  if (!stat2.isFile()) {
20866
21200
  throw new ToolError(`Path is not a file: ${absPath}`, {
20867
21201
  tool: "read_pdf"
@@ -20892,7 +21226,7 @@ Examples:
20892
21226
  }
20893
21227
  try {
20894
21228
  const pdfParse = await import('pdf-parse');
20895
- const dataBuffer = await fs28.readFile(absPath);
21229
+ const dataBuffer = await fs29.readFile(absPath);
20896
21230
  const pdfData = await pdfParse.default(dataBuffer, {
20897
21231
  max: maxPages
20898
21232
  });
@@ -20930,16 +21264,17 @@ Examples:
20930
21264
  tool: "read_pdf"
20931
21265
  });
20932
21266
  }
21267
+ const msg = error instanceof Error ? error.message : String(error);
20933
21268
  throw new ToolError(
20934
- `Failed to parse PDF: ${error instanceof Error ? error.message : String(error)}`,
21269
+ `Failed to parse PDF: ${msg}. The file may be encrypted, password-protected, or corrupted. Try opening it locally to verify.`,
20935
21270
  { tool: "read_pdf", cause: error instanceof Error ? error : void 0 }
20936
21271
  );
20937
21272
  }
20938
21273
  }
20939
21274
  });
20940
21275
  var pdfTools = [readPdfTool];
20941
- var fs29 = await import('fs/promises');
20942
- var path30 = await import('path');
21276
+ var fs30 = await import('fs/promises');
21277
+ var path31 = await import('path');
20943
21278
  var SUPPORTED_FORMATS = /* @__PURE__ */ new Set([".png", ".jpg", ".jpeg", ".gif", ".webp", ".bmp"]);
20944
21279
  var MAX_IMAGE_SIZE = 20 * 1024 * 1024;
20945
21280
  var MIME_TYPES = {
@@ -20967,15 +21302,15 @@ Examples:
20967
21302
  async execute({ path: filePath, prompt, provider }) {
20968
21303
  const startTime = performance.now();
20969
21304
  const effectivePrompt = prompt ?? "Describe this image in detail. If it's code or a UI, identify the key elements.";
20970
- const absPath = path30.resolve(filePath);
21305
+ const absPath = path31.resolve(filePath);
20971
21306
  const cwd = process.cwd();
20972
- if (!absPath.startsWith(cwd + path30.sep) && absPath !== cwd) {
21307
+ if (!absPath.startsWith(cwd + path31.sep) && absPath !== cwd) {
20973
21308
  throw new ToolError(
20974
21309
  `Path traversal denied: '${filePath}' resolves outside the project directory`,
20975
21310
  { tool: "read_image" }
20976
21311
  );
20977
21312
  }
20978
- const ext = path30.extname(absPath).toLowerCase();
21313
+ const ext = path31.extname(absPath).toLowerCase();
20979
21314
  if (!SUPPORTED_FORMATS.has(ext)) {
20980
21315
  throw new ToolError(
20981
21316
  `Unsupported image format '${ext}'. Supported: ${Array.from(SUPPORTED_FORMATS).join(", ")}`,
@@ -20983,7 +21318,7 @@ Examples:
20983
21318
  );
20984
21319
  }
20985
21320
  try {
20986
- const stat2 = await fs29.stat(absPath);
21321
+ const stat2 = await fs30.stat(absPath);
20987
21322
  if (!stat2.isFile()) {
20988
21323
  throw new ToolError(`Path is not a file: ${absPath}`, {
20989
21324
  tool: "read_image"
@@ -21004,7 +21339,7 @@ Examples:
21004
21339
  if (error instanceof ToolError) throw error;
21005
21340
  throw error;
21006
21341
  }
21007
- const imageBuffer = await fs29.readFile(absPath);
21342
+ const imageBuffer = await fs30.readFile(absPath);
21008
21343
  const base64 = imageBuffer.toString("base64");
21009
21344
  const mimeType = MIME_TYPES[ext] ?? "image/png";
21010
21345
  const selectedProvider = provider ?? "anthropic";
@@ -21096,10 +21431,15 @@ Examples:
21096
21431
  } catch (error) {
21097
21432
  if (error instanceof ToolError) throw error;
21098
21433
  if (error.message?.includes("Cannot find module") || error.message?.includes("MODULE_NOT_FOUND")) {
21099
- throw new ToolError(
21100
- `Provider SDK not installed for '${selectedProvider}'. Check your dependencies.`,
21101
- { tool: "read_image" }
21102
- );
21434
+ const pkgMap = {
21435
+ anthropic: "@anthropic-ai/sdk",
21436
+ openai: "openai",
21437
+ gemini: "@google/generative-ai"
21438
+ };
21439
+ const pkg = pkgMap[selectedProvider] ?? selectedProvider;
21440
+ throw new ToolError(`Provider SDK not installed. Run: pnpm add ${pkg}`, {
21441
+ tool: "read_image"
21442
+ });
21103
21443
  }
21104
21444
  throw new ToolError(
21105
21445
  `Image analysis failed: ${error instanceof Error ? error.message : String(error)}`,
@@ -21117,7 +21457,7 @@ Examples:
21117
21457
  }
21118
21458
  });
21119
21459
  var imageTools = [readImageTool];
21120
- var path31 = await import('path');
21460
+ var path32 = await import('path');
21121
21461
  var DANGEROUS_PATTERNS = [
21122
21462
  /\bDROP\s+(?:TABLE|DATABASE|INDEX|VIEW)\b/i,
21123
21463
  /\bTRUNCATE\b/i,
@@ -21148,7 +21488,7 @@ Examples:
21148
21488
  async execute({ database, query, params, readonly: isReadonlyParam }) {
21149
21489
  const isReadonly = isReadonlyParam ?? true;
21150
21490
  const startTime = performance.now();
21151
- const absPath = path31.resolve(database);
21491
+ const absPath = path32.resolve(database);
21152
21492
  if (isReadonly && isDangerousSql(query)) {
21153
21493
  throw new ToolError(
21154
21494
  "Write operations (INSERT, UPDATE, DELETE, DROP, ALTER, TRUNCATE, CREATE) are blocked in readonly mode. Set readonly: false to allow writes.",
@@ -21200,10 +21540,20 @@ Examples:
21200
21540
  { tool: "sql_query" }
21201
21541
  );
21202
21542
  }
21203
- throw new ToolError(
21204
- `SQL query failed: ${error instanceof Error ? error.message : String(error)}`,
21205
- { tool: "sql_query", cause: error instanceof Error ? error : void 0 }
21206
- );
21543
+ const msg = error instanceof Error ? error.message : String(error);
21544
+ let hint = `SQL query failed: ${msg}`;
21545
+ if (/no such table/i.test(msg))
21546
+ hint = `Table not found: ${msg}. Use inspect_schema to see available tables.`;
21547
+ else if (/syntax error|near "/i.test(msg))
21548
+ hint = `SQL syntax error: ${msg}. Check your query syntax.`;
21549
+ else if (/SQLITE_BUSY|database is locked/i.test(msg))
21550
+ hint = `Database is locked by another process. Wait and retry, or close other connections.`;
21551
+ else if (/unable to open database/i.test(msg))
21552
+ hint = `Cannot open database file. Use glob to verify the file path exists.`;
21553
+ throw new ToolError(hint, {
21554
+ tool: "sql_query",
21555
+ cause: error instanceof Error ? error : void 0
21556
+ });
21207
21557
  }
21208
21558
  }
21209
21559
  });
@@ -21221,7 +21571,7 @@ Examples:
21221
21571
  }),
21222
21572
  async execute({ database, table }) {
21223
21573
  const startTime = performance.now();
21224
- const absPath = path31.resolve(database);
21574
+ const absPath = path32.resolve(database);
21225
21575
  try {
21226
21576
  const { default: Database } = await import('better-sqlite3');
21227
21577
  const db = new Database(absPath, { readonly: true, fileMustExist: true });
@@ -21266,22 +21616,28 @@ Examples:
21266
21616
  { tool: "inspect_schema" }
21267
21617
  );
21268
21618
  }
21269
- throw new ToolError(
21270
- `Schema inspection failed: ${error instanceof Error ? error.message : String(error)}`,
21271
- { tool: "inspect_schema", cause: error instanceof Error ? error : void 0 }
21272
- );
21619
+ const msg = error instanceof Error ? error.message : String(error);
21620
+ let hint = `Schema inspection failed: ${msg}`;
21621
+ if (/unable to open database/i.test(msg))
21622
+ hint = `Cannot open database file. Use glob to verify the file path exists.`;
21623
+ else if (/no such table/i.test(msg))
21624
+ hint = `Table '${table ?? ""}' not found. Run inspect_schema without a table name to list all tables.`;
21625
+ throw new ToolError(hint, {
21626
+ tool: "inspect_schema",
21627
+ cause: error instanceof Error ? error : void 0
21628
+ });
21273
21629
  }
21274
21630
  }
21275
21631
  });
21276
21632
  var databaseTools = [sqlQueryTool, inspectSchemaTool];
21277
- var fs30 = await import('fs/promises');
21278
- var path32 = await import('path');
21633
+ var fs31 = await import('fs/promises');
21634
+ var path33 = await import('path');
21279
21635
  var AnalyzeFileSchema = z.object({
21280
21636
  filePath: z.string().describe("Path to file to analyze"),
21281
21637
  includeAst: z.boolean().default(false).describe("Include AST in result")
21282
21638
  });
21283
21639
  async function analyzeFile(filePath, includeAst = false) {
21284
- const content = await fs30.readFile(filePath, "utf-8");
21640
+ const content = await fs31.readFile(filePath, "utf-8");
21285
21641
  const lines = content.split("\n").length;
21286
21642
  const functions = [];
21287
21643
  const classes = [];
@@ -21385,10 +21741,10 @@ async function analyzeDirectory(dirPath) {
21385
21741
  try {
21386
21742
  const analysis = await analyzeFile(file, false);
21387
21743
  totalLines += analysis.lines;
21388
- const ext = path32.extname(file);
21744
+ const ext = path33.extname(file);
21389
21745
  filesByType[ext] = (filesByType[ext] || 0) + 1;
21390
21746
  fileStats.push({
21391
- file: path32.relative(dirPath, file),
21747
+ file: path33.relative(dirPath, file),
21392
21748
  lines: analysis.lines,
21393
21749
  complexity: analysis.complexity.cyclomatic
21394
21750
  });
@@ -21711,13 +22067,13 @@ ${completed.map((r) => `- ${r.agentId}: Success`).join("\n")}`;
21711
22067
  }
21712
22068
  });
21713
22069
  var agentCoordinatorTools = [createAgentPlanTool, delegateTaskTool, aggregateResultsTool];
21714
- var fs31 = await import('fs/promises');
22070
+ var fs32 = await import('fs/promises');
21715
22071
  var SuggestImprovementsSchema = z.object({
21716
22072
  filePath: z.string().describe("File to analyze for improvement suggestions"),
21717
22073
  context: z.string().optional().describe("Additional context about the code")
21718
22074
  });
21719
22075
  async function analyzeAndSuggest(filePath, _context) {
21720
- const content = await fs31.readFile(filePath, "utf-8");
22076
+ const content = await fs32.readFile(filePath, "utf-8");
21721
22077
  const lines = content.split("\n");
21722
22078
  const suggestions = [];
21723
22079
  for (let i = 0; i < lines.length; i++) {
@@ -21809,7 +22165,7 @@ async function analyzeAndSuggest(filePath, _context) {
21809
22165
  if (filePath.endsWith(".ts") && !filePath.includes("test") && !filePath.includes(".d.ts") && line.includes("export ")) {
21810
22166
  const testPath = filePath.replace(".ts", ".test.ts");
21811
22167
  try {
21812
- await fs31.access(testPath);
22168
+ await fs32.access(testPath);
21813
22169
  } catch {
21814
22170
  suggestions.push({
21815
22171
  type: "testing",
@@ -21866,7 +22222,7 @@ var calculateCodeScoreTool = defineTool({
21866
22222
  async execute(input) {
21867
22223
  const { filePath } = input;
21868
22224
  const suggestions = await analyzeAndSuggest(filePath);
21869
- const content = await fs31.readFile(filePath, "utf-8");
22225
+ const content = await fs32.readFile(filePath, "utf-8");
21870
22226
  const lines = content.split("\n");
21871
22227
  const nonEmptyLines = lines.filter((l) => l.trim()).length;
21872
22228
  let score = 100;
@@ -21900,8 +22256,8 @@ var calculateCodeScoreTool = defineTool({
21900
22256
  }
21901
22257
  });
21902
22258
  var smartSuggestionsTools = [suggestImprovementsTool, calculateCodeScoreTool];
21903
- var fs32 = await import('fs/promises');
21904
- var path33 = await import('path');
22259
+ var fs33 = await import('fs/promises');
22260
+ var path34 = await import('path');
21905
22261
  var ContextMemoryStore = class {
21906
22262
  items = /* @__PURE__ */ new Map();
21907
22263
  learnings = /* @__PURE__ */ new Map();
@@ -21913,7 +22269,7 @@ var ContextMemoryStore = class {
21913
22269
  }
21914
22270
  async load() {
21915
22271
  try {
21916
- const content = await fs32.readFile(this.storePath, "utf-8");
22272
+ const content = await fs33.readFile(this.storePath, "utf-8");
21917
22273
  const data = JSON.parse(content);
21918
22274
  this.items = new Map(Object.entries(data.items || {}));
21919
22275
  this.learnings = new Map(Object.entries(data.learnings || {}));
@@ -21921,15 +22277,15 @@ var ContextMemoryStore = class {
21921
22277
  }
21922
22278
  }
21923
22279
  async save() {
21924
- const dir = path33.dirname(this.storePath);
21925
- await fs32.mkdir(dir, { recursive: true });
22280
+ const dir = path34.dirname(this.storePath);
22281
+ await fs33.mkdir(dir, { recursive: true });
21926
22282
  const data = {
21927
22283
  sessionId: this.sessionId,
21928
22284
  items: Object.fromEntries(this.items),
21929
22285
  learnings: Object.fromEntries(this.learnings),
21930
22286
  savedAt: Date.now()
21931
22287
  };
21932
- await fs32.writeFile(this.storePath, JSON.stringify(data, null, 2));
22288
+ await fs33.writeFile(this.storePath, JSON.stringify(data, null, 2));
21933
22289
  }
21934
22290
  addContext(id, item) {
21935
22291
  this.items.set(id, item);
@@ -22094,11 +22450,11 @@ var contextEnhancerTools = [
22094
22450
  recordLearningTool,
22095
22451
  getLearnedPatternsTool
22096
22452
  ];
22097
- var fs33 = await import('fs/promises');
22098
- var path34 = await import('path');
22453
+ var fs34 = await import('fs/promises');
22454
+ var path35 = await import('path');
22099
22455
  async function discoverSkills(skillsDir) {
22100
22456
  try {
22101
- const files = await fs33.readdir(skillsDir);
22457
+ const files = await fs34.readdir(skillsDir);
22102
22458
  return files.filter((f) => f.endsWith(".ts") || f.endsWith(".js"));
22103
22459
  } catch {
22104
22460
  return [];
@@ -22106,12 +22462,12 @@ async function discoverSkills(skillsDir) {
22106
22462
  }
22107
22463
  async function loadSkillMetadata(skillPath) {
22108
22464
  try {
22109
- const content = await fs33.readFile(skillPath, "utf-8");
22465
+ const content = await fs34.readFile(skillPath, "utf-8");
22110
22466
  const nameMatch = content.match(/@name\s+(\S+)/);
22111
22467
  const descMatch = content.match(/@description\s+(.+)/);
22112
22468
  const versionMatch = content.match(/@version\s+(\S+)/);
22113
22469
  return {
22114
- name: nameMatch?.[1] || path34.basename(skillPath, path34.extname(skillPath)),
22470
+ name: nameMatch?.[1] || path35.basename(skillPath, path35.extname(skillPath)),
22115
22471
  description: descMatch?.[1] || "No description",
22116
22472
  version: versionMatch?.[1] || "1.0.0",
22117
22473
  dependencies: []
@@ -22155,7 +22511,7 @@ var discoverSkillsTool = defineTool({
22155
22511
  const { skillsDir } = input;
22156
22512
  const skills = await discoverSkills(skillsDir);
22157
22513
  const metadata = await Promise.all(
22158
- skills.map((s) => loadSkillMetadata(path34.join(skillsDir, s)))
22514
+ skills.map((s) => loadSkillMetadata(path35.join(skillsDir, s)))
22159
22515
  );
22160
22516
  return {
22161
22517
  skillsDir,
@@ -22656,8 +23012,8 @@ function hasNullByte2(str) {
22656
23012
  }
22657
23013
  function isBlockedPath(absolute) {
22658
23014
  for (const blocked of BLOCKED_PATHS2) {
22659
- const normalizedBlocked = path15__default.normalize(blocked);
22660
- if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked + path15__default.sep)) {
23015
+ const normalizedBlocked = path16__default.normalize(blocked);
23016
+ if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked + path16__default.sep)) {
22661
23017
  return blocked;
22662
23018
  }
22663
23019
  }
@@ -22675,7 +23031,7 @@ function getInterpreter(ext) {
22675
23031
  }
22676
23032
  async function isExecutable(filePath) {
22677
23033
  try {
22678
- await fs14__default.access(filePath, fs14__default.constants.X_OK);
23034
+ await fs15__default.access(filePath, fs15__default.constants.X_OK);
22679
23035
  return true;
22680
23036
  } catch {
22681
23037
  return false;
@@ -22715,7 +23071,7 @@ Examples:
22715
23071
  throw new ToolError("Invalid file path", { tool: "open_file" });
22716
23072
  }
22717
23073
  const workDir = cwd ?? process.cwd();
22718
- const absolute = path15__default.isAbsolute(filePath) ? path15__default.normalize(filePath) : path15__default.resolve(workDir, filePath);
23074
+ const absolute = path16__default.isAbsolute(filePath) ? path16__default.normalize(filePath) : path16__default.resolve(workDir, filePath);
22719
23075
  const blockedBy = isBlockedPath(absolute);
22720
23076
  if (blockedBy) {
22721
23077
  throw new ToolError(`Access to system path '${blockedBy}' is not allowed`, {
@@ -22723,7 +23079,7 @@ Examples:
22723
23079
  });
22724
23080
  }
22725
23081
  try {
22726
- await fs14__default.access(absolute);
23082
+ await fs15__default.access(absolute);
22727
23083
  } catch {
22728
23084
  throw new ToolError(`File not found: ${absolute}`, { tool: "open_file" });
22729
23085
  }
@@ -22738,14 +23094,14 @@ Examples:
22738
23094
  };
22739
23095
  }
22740
23096
  if (isBlockedExecFile(absolute)) {
22741
- throw new ToolError(`Execution of sensitive file is blocked: ${path15__default.basename(absolute)}`, {
23097
+ throw new ToolError(`Execution of sensitive file is blocked: ${path16__default.basename(absolute)}`, {
22742
23098
  tool: "open_file"
22743
23099
  });
22744
23100
  }
22745
23101
  if (args.length > 0 && hasDangerousArgs(args)) {
22746
23102
  throw new ToolError("Arguments contain dangerous patterns", { tool: "open_file" });
22747
23103
  }
22748
- const ext = path15__default.extname(absolute);
23104
+ const ext = path16__default.extname(absolute);
22749
23105
  const interpreter = getInterpreter(ext);
22750
23106
  const executable = await isExecutable(absolute);
22751
23107
  let command;
@@ -22758,7 +23114,7 @@ Examples:
22758
23114
  cmdArgs = [...args];
22759
23115
  } else {
22760
23116
  throw new ToolError(
22761
- `Cannot execute '${path15__default.basename(absolute)}': no known interpreter for '${ext || "(no extension)"}' and file is not executable`,
23117
+ `Cannot execute '${path16__default.basename(absolute)}': no known interpreter for '${ext || "(no extension)"}' and file is not executable`,
22762
23118
  { tool: "open_file" }
22763
23119
  );
22764
23120
  }
@@ -22810,7 +23166,7 @@ Examples:
22810
23166
  reason: z.string().optional().describe("Why access is needed (shown to user for context)")
22811
23167
  }),
22812
23168
  async execute({ path: dirPath, reason }) {
22813
- const absolute = path15__default.resolve(dirPath);
23169
+ const absolute = path16__default.resolve(dirPath);
22814
23170
  if (isWithinAllowedPath(absolute, "read")) {
22815
23171
  return {
22816
23172
  authorized: true,
@@ -22819,8 +23175,8 @@ Examples:
22819
23175
  };
22820
23176
  }
22821
23177
  for (const blocked of BLOCKED_SYSTEM_PATHS) {
22822
- const normalizedBlocked = path15__default.normalize(blocked);
22823
- if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked + path15__default.sep)) {
23178
+ const normalizedBlocked = path16__default.normalize(blocked);
23179
+ if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked + path16__default.sep)) {
22824
23180
  return {
22825
23181
  authorized: false,
22826
23182
  path: absolute,
@@ -22829,7 +23185,7 @@ Examples:
22829
23185
  }
22830
23186
  }
22831
23187
  const cwd = process.cwd();
22832
- if (absolute === path15__default.normalize(cwd) || absolute.startsWith(path15__default.normalize(cwd) + path15__default.sep)) {
23188
+ if (absolute === path16__default.normalize(cwd) || absolute.startsWith(path16__default.normalize(cwd) + path16__default.sep)) {
22833
23189
  return {
22834
23190
  authorized: true,
22835
23191
  path: absolute,
@@ -22837,7 +23193,7 @@ Examples:
22837
23193
  };
22838
23194
  }
22839
23195
  try {
22840
- const stat2 = await fs14__default.stat(absolute);
23196
+ const stat2 = await fs15__default.stat(absolute);
22841
23197
  if (!stat2.isDirectory()) {
22842
23198
  return {
22843
23199
  authorized: false,
@@ -22853,7 +23209,7 @@ Examples:
22853
23209
  };
22854
23210
  }
22855
23211
  const existing = getAllowedPaths();
22856
- if (existing.some((e) => path15__default.normalize(e.path) === path15__default.normalize(absolute))) {
23212
+ if (existing.some((e) => path16__default.normalize(e.path) === path16__default.normalize(absolute))) {
22857
23213
  return {
22858
23214
  authorized: true,
22859
23215
  path: absolute,